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/voice_engine/voe_audio_processing_impl.h" 12 13 #include "webrtc/modules/audio_processing/include/audio_processing.h" 14 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 15 #include "webrtc/system_wrappers/interface/logging.h" 16 #include "webrtc/system_wrappers/interface/trace.h" 17 #include "webrtc/voice_engine/channel.h" 18 #include "webrtc/voice_engine/include/voe_errors.h" 19 #include "webrtc/voice_engine/transmit_mixer.h" 20 #include "webrtc/voice_engine/voice_engine_impl.h" 21 22 // TODO(andrew): move to a common place. 23 #define WEBRTC_VOICE_INIT_CHECK() \ 24 do { \ 25 if (!_shared->statistics().Initialized()) { \ 26 _shared->SetLastError(VE_NOT_INITED, kTraceError); \ 27 return -1; \ 28 } \ 29 } while (0) 30 31 #define WEBRTC_VOICE_INIT_CHECK_BOOL() \ 32 do { \ 33 if (!_shared->statistics().Initialized()) { \ 34 _shared->SetLastError(VE_NOT_INITED, kTraceError); \ 35 return false; \ 36 } \ 37 } while (0) 38 39 namespace webrtc { 40 41 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) 42 static const EcModes kDefaultEcMode = kEcAecm; 43 #else 44 static const EcModes kDefaultEcMode = kEcAec; 45 #endif 46 47 VoEAudioProcessing* VoEAudioProcessing::GetInterface(VoiceEngine* voiceEngine) { 48 #ifndef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API 49 return NULL; 50 #else 51 if (NULL == voiceEngine) { 52 return NULL; 53 } 54 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); 55 s->AddRef(); 56 return s; 57 #endif 58 } 59 60 #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API 61 VoEAudioProcessingImpl::VoEAudioProcessingImpl(voe::SharedData* shared) 62 : _isAecMode(kDefaultEcMode == kEcAec), 63 _shared(shared) { 64 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), 65 "VoEAudioProcessingImpl::VoEAudioProcessingImpl() - ctor"); 66 } 67 68 VoEAudioProcessingImpl::~VoEAudioProcessingImpl() { 69 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), 70 "VoEAudioProcessingImpl::~VoEAudioProcessingImpl() - dtor"); 71 } 72 73 int VoEAudioProcessingImpl::SetNsStatus(bool enable, NsModes mode) { 74 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 75 "SetNsStatus(enable=%d, mode=%d)", enable, mode); 76 #ifdef WEBRTC_VOICE_ENGINE_NR 77 if (!_shared->statistics().Initialized()) { 78 _shared->SetLastError(VE_NOT_INITED, kTraceError); 79 return -1; 80 } 81 82 NoiseSuppression::Level nsLevel = kDefaultNsMode; 83 switch (mode) { 84 case kNsDefault: 85 nsLevel = kDefaultNsMode; 86 break; 87 case kNsUnchanged: 88 nsLevel = _shared->audio_processing()->noise_suppression()->level(); 89 break; 90 case kNsConference: 91 nsLevel = NoiseSuppression::kHigh; 92 break; 93 case kNsLowSuppression: 94 nsLevel = NoiseSuppression::kLow; 95 break; 96 case kNsModerateSuppression: 97 nsLevel = NoiseSuppression::kModerate; 98 break; 99 case kNsHighSuppression: 100 nsLevel = NoiseSuppression::kHigh; 101 break; 102 case kNsVeryHighSuppression: 103 nsLevel = NoiseSuppression::kVeryHigh; 104 break; 105 } 106 107 if (_shared->audio_processing()->noise_suppression()-> 108 set_level(nsLevel) != 0) { 109 _shared->SetLastError(VE_APM_ERROR, kTraceError, 110 "SetNsStatus() failed to set Ns mode"); 111 return -1; 112 } 113 if (_shared->audio_processing()->noise_suppression()->Enable(enable) != 0) { 114 _shared->SetLastError(VE_APM_ERROR, kTraceError, 115 "SetNsStatus() failed to set Ns state"); 116 return -1; 117 } 118 119 return 0; 120 #else 121 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 122 "SetNsStatus() Ns is not supported"); 123 return -1; 124 #endif 125 } 126 127 int VoEAudioProcessingImpl::GetNsStatus(bool& enabled, NsModes& mode) { 128 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 129 "GetNsStatus(enabled=?, mode=?)"); 130 #ifdef WEBRTC_VOICE_ENGINE_NR 131 if (!_shared->statistics().Initialized()) { 132 _shared->SetLastError(VE_NOT_INITED, kTraceError); 133 return -1; 134 } 135 136 enabled = _shared->audio_processing()->noise_suppression()->is_enabled(); 137 NoiseSuppression::Level nsLevel = 138 _shared->audio_processing()->noise_suppression()->level(); 139 140 switch (nsLevel) { 141 case NoiseSuppression::kLow: 142 mode = kNsLowSuppression; 143 break; 144 case NoiseSuppression::kModerate: 145 mode = kNsModerateSuppression; 146 break; 147 case NoiseSuppression::kHigh: 148 mode = kNsHighSuppression; 149 break; 150 case NoiseSuppression::kVeryHigh: 151 mode = kNsVeryHighSuppression; 152 break; 153 } 154 155 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 156 "GetNsStatus() => enabled=% d, mode=%d", enabled, mode); 157 return 0; 158 #else 159 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 160 "GetNsStatus() Ns is not supported"); 161 return -1; 162 #endif 163 } 164 165 int VoEAudioProcessingImpl::SetAgcStatus(bool enable, AgcModes mode) { 166 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 167 "SetAgcStatus(enable=%d, mode=%d)", enable, mode); 168 #ifdef WEBRTC_VOICE_ENGINE_AGC 169 if (!_shared->statistics().Initialized()) { 170 _shared->SetLastError(VE_NOT_INITED, kTraceError); 171 return -1; 172 } 173 174 #if defined(WEBRTC_IOS) || defined(ATA) || defined(WEBRTC_ANDROID) 175 if (mode == kAgcAdaptiveAnalog) { 176 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 177 "SetAgcStatus() invalid Agc mode for mobile device"); 178 return -1; 179 } 180 #endif 181 182 GainControl::Mode agcMode = kDefaultAgcMode; 183 switch (mode) { 184 case kAgcDefault: 185 agcMode = kDefaultAgcMode; 186 break; 187 case kAgcUnchanged: 188 agcMode = _shared->audio_processing()->gain_control()->mode(); 189 break; 190 case kAgcFixedDigital: 191 agcMode = GainControl::kFixedDigital; 192 break; 193 case kAgcAdaptiveAnalog: 194 agcMode = GainControl::kAdaptiveAnalog; 195 break; 196 case kAgcAdaptiveDigital: 197 agcMode = GainControl::kAdaptiveDigital; 198 break; 199 } 200 201 if (_shared->audio_processing()->gain_control()->set_mode(agcMode) != 0) { 202 _shared->SetLastError(VE_APM_ERROR, kTraceError, 203 "SetAgcStatus() failed to set Agc mode"); 204 return -1; 205 } 206 if (_shared->audio_processing()->gain_control()->Enable(enable) != 0) { 207 _shared->SetLastError(VE_APM_ERROR, kTraceError, 208 "SetAgcStatus() failed to set Agc state"); 209 return -1; 210 } 211 212 if (agcMode != GainControl::kFixedDigital) { 213 // Set Agc state in the ADM when adaptive Agc mode has been selected. 214 // Note that we also enable the ADM Agc when Adaptive Digital mode is 215 // used since we want to be able to provide the APM with updated mic 216 // levels when the user modifies the mic level manually. 217 if (_shared->audio_device()->SetAGC(enable) != 0) { 218 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, 219 kTraceWarning, "SetAgcStatus() failed to set Agc mode"); 220 } 221 } 222 223 return 0; 224 #else 225 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 226 "SetAgcStatus() Agc is not supported"); 227 return -1; 228 #endif 229 } 230 231 int VoEAudioProcessingImpl::GetAgcStatus(bool& enabled, AgcModes& mode) { 232 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 233 "GetAgcStatus(enabled=?, mode=?)"); 234 #ifdef WEBRTC_VOICE_ENGINE_AGC 235 if (!_shared->statistics().Initialized()) { 236 _shared->SetLastError(VE_NOT_INITED, kTraceError); 237 return -1; 238 } 239 240 enabled = _shared->audio_processing()->gain_control()->is_enabled(); 241 GainControl::Mode agcMode = 242 _shared->audio_processing()->gain_control()->mode(); 243 244 switch (agcMode) { 245 case GainControl::kFixedDigital: 246 mode = kAgcFixedDigital; 247 break; 248 case GainControl::kAdaptiveAnalog: 249 mode = kAgcAdaptiveAnalog; 250 break; 251 case GainControl::kAdaptiveDigital: 252 mode = kAgcAdaptiveDigital; 253 break; 254 } 255 256 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 257 "GetAgcStatus() => enabled=%d, mode=%d", enabled, mode); 258 return 0; 259 #else 260 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 261 "GetAgcStatus() Agc is not supported"); 262 return -1; 263 #endif 264 } 265 266 int VoEAudioProcessingImpl::SetAgcConfig(AgcConfig config) { 267 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 268 "SetAgcConfig()"); 269 #ifdef WEBRTC_VOICE_ENGINE_AGC 270 if (!_shared->statistics().Initialized()) { 271 _shared->SetLastError(VE_NOT_INITED, kTraceError); 272 return -1; 273 } 274 275 if (_shared->audio_processing()->gain_control()->set_target_level_dbfs( 276 config.targetLeveldBOv) != 0) { 277 _shared->SetLastError(VE_APM_ERROR, kTraceError, 278 "SetAgcConfig() failed to set target peak |level|" 279 " (or envelope) of the Agc"); 280 return -1; 281 } 282 if (_shared->audio_processing()->gain_control()->set_compression_gain_db( 283 config.digitalCompressionGaindB) != 0) { 284 _shared->SetLastError(VE_APM_ERROR, kTraceError, 285 "SetAgcConfig() failed to set the range in |gain| " 286 "the digital compression stage may apply"); 287 return -1; 288 } 289 if (_shared->audio_processing()->gain_control()->enable_limiter( 290 config.limiterEnable) != 0) { 291 _shared->SetLastError(VE_APM_ERROR, kTraceError, 292 "SetAgcConfig() failed to set hard limiter to the signal"); 293 return -1; 294 } 295 296 return 0; 297 #else 298 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 299 "SetAgcConfig() EC is not supported"); 300 return -1; 301 #endif 302 } 303 304 int VoEAudioProcessingImpl::GetAgcConfig(AgcConfig& config) { 305 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 306 "GetAgcConfig(config=?)"); 307 #ifdef WEBRTC_VOICE_ENGINE_AGC 308 if (!_shared->statistics().Initialized()) { 309 _shared->SetLastError(VE_NOT_INITED, kTraceError); 310 return -1; 311 } 312 313 config.targetLeveldBOv = 314 _shared->audio_processing()->gain_control()->target_level_dbfs(); 315 config.digitalCompressionGaindB = 316 _shared->audio_processing()->gain_control()->compression_gain_db(); 317 config.limiterEnable = 318 _shared->audio_processing()->gain_control()->is_limiter_enabled(); 319 320 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 321 "GetAgcConfig() => targetLeveldBOv=%u, " 322 "digitalCompressionGaindB=%u, limiterEnable=%d", 323 config.targetLeveldBOv, 324 config.digitalCompressionGaindB, 325 config.limiterEnable); 326 327 return 0; 328 #else 329 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 330 "GetAgcConfig() EC is not supported"); 331 return -1; 332 #endif 333 } 334 335 int VoEAudioProcessingImpl::SetRxNsStatus(int channel, 336 bool enable, 337 NsModes mode) { 338 LOG_API3(channel, enable, mode); 339 #ifdef WEBRTC_VOICE_ENGINE_NR 340 if (!_shared->statistics().Initialized()) { 341 _shared->SetLastError(VE_NOT_INITED, kTraceError); 342 return -1; 343 } 344 345 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 346 voe::Channel* channelPtr = ch.channel(); 347 if (channelPtr == NULL) { 348 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 349 "SetRxNsStatus() failed to locate channel"); 350 return -1; 351 } 352 return channelPtr->SetRxNsStatus(enable, mode); 353 #else 354 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 355 "SetRxNsStatus() NS is not supported"); 356 return -1; 357 #endif 358 } 359 360 int VoEAudioProcessingImpl::GetRxNsStatus(int channel, 361 bool& enabled, 362 NsModes& mode) { 363 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 364 "GetRxNsStatus(channel=%d, enable=?, mode=?)", channel); 365 #ifdef WEBRTC_VOICE_ENGINE_NR 366 if (!_shared->statistics().Initialized()) { 367 _shared->SetLastError(VE_NOT_INITED, kTraceError); 368 return -1; 369 } 370 371 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 372 voe::Channel* channelPtr = ch.channel(); 373 if (channelPtr == NULL) { 374 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 375 "GetRxNsStatus() failed to locate channel"); 376 return -1; 377 } 378 return channelPtr->GetRxNsStatus(enabled, mode); 379 #else 380 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 381 "GetRxNsStatus() NS is not supported"); 382 return -1; 383 #endif 384 } 385 386 int VoEAudioProcessingImpl::SetRxAgcStatus(int channel, 387 bool enable, 388 AgcModes mode) { 389 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 390 "SetRxAgcStatus(channel=%d, enable=%d, mode=%d)", 391 channel, (int)enable, (int)mode); 392 #ifdef WEBRTC_VOICE_ENGINE_AGC 393 if (!_shared->statistics().Initialized()) { 394 _shared->SetLastError(VE_NOT_INITED, kTraceError); 395 return -1; 396 } 397 398 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 399 voe::Channel* channelPtr = ch.channel(); 400 if (channelPtr == NULL) { 401 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 402 "SetRxAgcStatus() failed to locate channel"); 403 return -1; 404 } 405 return channelPtr->SetRxAgcStatus(enable, mode); 406 #else 407 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 408 "SetRxAgcStatus() Agc is not supported"); 409 return -1; 410 #endif 411 } 412 413 int VoEAudioProcessingImpl::GetRxAgcStatus(int channel, 414 bool& enabled, 415 AgcModes& mode) { 416 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 417 "GetRxAgcStatus(channel=%d, enable=?, mode=?)", channel); 418 #ifdef WEBRTC_VOICE_ENGINE_AGC 419 if (!_shared->statistics().Initialized()) { 420 _shared->SetLastError(VE_NOT_INITED, kTraceError); 421 return -1; 422 } 423 424 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 425 voe::Channel* channelPtr = ch.channel(); 426 if (channelPtr == NULL) { 427 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 428 "GetRxAgcStatus() failed to locate channel"); 429 return -1; 430 } 431 return channelPtr->GetRxAgcStatus(enabled, mode); 432 #else 433 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 434 "GetRxAgcStatus() Agc is not supported"); 435 return -1; 436 #endif 437 } 438 439 int VoEAudioProcessingImpl::SetRxAgcConfig(int channel, 440 AgcConfig config) { 441 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 442 "SetRxAgcConfig(channel=%d)", channel); 443 #ifdef WEBRTC_VOICE_ENGINE_AGC 444 if (!_shared->statistics().Initialized()) { 445 _shared->SetLastError(VE_NOT_INITED, kTraceError); 446 return -1; 447 } 448 449 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 450 voe::Channel* channelPtr = ch.channel(); 451 if (channelPtr == NULL) { 452 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 453 "SetRxAgcConfig() failed to locate channel"); 454 return -1; 455 } 456 return channelPtr->SetRxAgcConfig(config); 457 #else 458 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 459 "SetRxAgcConfig() Agc is not supported"); 460 return -1; 461 #endif 462 } 463 464 int VoEAudioProcessingImpl::GetRxAgcConfig(int channel, AgcConfig& config) { 465 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 466 "GetRxAgcConfig(channel=%d)", channel); 467 #ifdef WEBRTC_VOICE_ENGINE_AGC 468 if (!_shared->statistics().Initialized()) { 469 _shared->SetLastError(VE_NOT_INITED, kTraceError); 470 return -1; 471 } 472 473 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 474 voe::Channel* channelPtr = ch.channel(); 475 if (channelPtr == NULL) { 476 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 477 "GetRxAgcConfig() failed to locate channel"); 478 return -1; 479 } 480 return channelPtr->GetRxAgcConfig(config); 481 #else 482 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 483 "GetRxAgcConfig() Agc is not supported"); 484 return -1; 485 #endif 486 } 487 488 bool VoEAudioProcessing::DriftCompensationSupported() { 489 #if defined(WEBRTC_DRIFT_COMPENSATION_SUPPORTED) 490 return true; 491 #else 492 return false; 493 #endif 494 } 495 496 int VoEAudioProcessingImpl::EnableDriftCompensation(bool enable) { 497 LOG_API1(enable); 498 WEBRTC_VOICE_INIT_CHECK(); 499 500 if (!DriftCompensationSupported()) { 501 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 502 "Drift compensation is not supported on this platform."); 503 return -1; 504 } 505 506 EchoCancellation* aec = _shared->audio_processing()->echo_cancellation(); 507 if (aec->enable_drift_compensation(enable) != 0) { 508 _shared->SetLastError(VE_APM_ERROR, kTraceError, 509 "aec->enable_drift_compensation() failed"); 510 return -1; 511 } 512 return 0; 513 } 514 515 bool VoEAudioProcessingImpl::DriftCompensationEnabled() { 516 LOG_API0(); 517 WEBRTC_VOICE_INIT_CHECK_BOOL(); 518 519 EchoCancellation* aec = _shared->audio_processing()->echo_cancellation(); 520 return aec->is_drift_compensation_enabled(); 521 } 522 523 int VoEAudioProcessingImpl::SetEcStatus(bool enable, EcModes mode) { 524 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 525 "SetEcStatus(enable=%d, mode=%d)", enable, mode); 526 #ifdef WEBRTC_VOICE_ENGINE_ECHO 527 if (!_shared->statistics().Initialized()) { 528 _shared->SetLastError(VE_NOT_INITED, kTraceError); 529 return -1; 530 } 531 532 // AEC mode 533 if ((mode == kEcDefault) || 534 (mode == kEcConference) || 535 (mode == kEcAec) || 536 ((mode == kEcUnchanged) && 537 (_isAecMode == true))) { 538 if (enable) { 539 // Disable the AECM before enable the AEC 540 if (_shared->audio_processing()->echo_control_mobile()->is_enabled()) { 541 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 542 "SetEcStatus() disable AECM before enabling AEC"); 543 if (_shared->audio_processing()->echo_control_mobile()-> 544 Enable(false) != 0) { 545 _shared->SetLastError(VE_APM_ERROR, kTraceError, 546 "SetEcStatus() failed to disable AECM"); 547 return -1; 548 } 549 } 550 } 551 if (_shared->audio_processing()->echo_cancellation()->Enable(enable) != 0) { 552 _shared->SetLastError(VE_APM_ERROR, kTraceError, 553 "SetEcStatus() failed to set AEC state"); 554 return -1; 555 } 556 if (mode == kEcConference) { 557 if (_shared->audio_processing()->echo_cancellation()-> 558 set_suppression_level(EchoCancellation::kHighSuppression) != 0) { 559 _shared->SetLastError(VE_APM_ERROR, kTraceError, 560 "SetEcStatus() failed to set aggressiveness to high"); 561 return -1; 562 } 563 } else { 564 if (_shared->audio_processing()->echo_cancellation()-> 565 set_suppression_level( 566 EchoCancellation::kModerateSuppression) != 0) { 567 _shared->SetLastError(VE_APM_ERROR, kTraceError, 568 "SetEcStatus() failed to set aggressiveness to moderate"); 569 return -1; 570 } 571 } 572 573 _isAecMode = true; 574 } else if ((mode == kEcAecm) || 575 ((mode == kEcUnchanged) && 576 (_isAecMode == false))) { 577 if (enable) { 578 // Disable the AEC before enable the AECM 579 if (_shared->audio_processing()->echo_cancellation()->is_enabled()) { 580 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 581 "SetEcStatus() disable AEC before enabling AECM"); 582 if (_shared->audio_processing()->echo_cancellation()-> 583 Enable(false) != 0) { 584 _shared->SetLastError(VE_APM_ERROR, kTraceError, 585 "SetEcStatus() failed to disable AEC"); 586 return -1; 587 } 588 } 589 } 590 if (_shared->audio_processing()->echo_control_mobile()-> 591 Enable(enable) != 0) { 592 _shared->SetLastError(VE_APM_ERROR, kTraceError, 593 "SetEcStatus() failed to set AECM state"); 594 return -1; 595 } 596 _isAecMode = false; 597 } else { 598 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, 599 "SetEcStatus() invalid EC mode"); 600 return -1; 601 } 602 603 return 0; 604 #else 605 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 606 "SetEcStatus() EC is not supported"); 607 return -1; 608 #endif 609 } 610 611 int VoEAudioProcessingImpl::GetEcStatus(bool& enabled, EcModes& mode) { 612 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 613 "GetEcStatus()"); 614 #ifdef WEBRTC_VOICE_ENGINE_ECHO 615 if (!_shared->statistics().Initialized()) { 616 _shared->SetLastError(VE_NOT_INITED, kTraceError); 617 return -1; 618 } 619 620 if (_isAecMode == true) { 621 mode = kEcAec; 622 enabled = _shared->audio_processing()->echo_cancellation()->is_enabled(); 623 } else { 624 mode = kEcAecm; 625 enabled = _shared->audio_processing()->echo_control_mobile()-> 626 is_enabled(); 627 } 628 629 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 630 "GetEcStatus() => enabled=%i, mode=%i", 631 enabled, (int)mode); 632 return 0; 633 #else 634 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 635 "GetEcStatus() EC is not supported"); 636 return -1; 637 #endif 638 } 639 640 void VoEAudioProcessingImpl::SetDelayOffsetMs(int offset) { 641 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 642 "SetDelayOffsetMs(offset = %d)", offset); 643 _shared->audio_processing()->set_delay_offset_ms(offset); 644 } 645 646 int VoEAudioProcessingImpl::DelayOffsetMs() { 647 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 648 "DelayOffsetMs()"); 649 return _shared->audio_processing()->delay_offset_ms(); 650 } 651 652 int VoEAudioProcessingImpl::SetAecmMode(AecmModes mode, bool enableCNG) { 653 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 654 "SetAECMMode(mode = %d)", mode); 655 #ifdef WEBRTC_VOICE_ENGINE_ECHO 656 if (!_shared->statistics().Initialized()) { 657 _shared->SetLastError(VE_NOT_INITED, kTraceError); 658 return -1; 659 } 660 661 EchoControlMobile::RoutingMode aecmMode( 662 EchoControlMobile::kQuietEarpieceOrHeadset); 663 664 switch (mode) { 665 case kAecmQuietEarpieceOrHeadset: 666 aecmMode = EchoControlMobile::kQuietEarpieceOrHeadset; 667 break; 668 case kAecmEarpiece: 669 aecmMode = EchoControlMobile::kEarpiece; 670 break; 671 case kAecmLoudEarpiece: 672 aecmMode = EchoControlMobile::kLoudEarpiece; 673 break; 674 case kAecmSpeakerphone: 675 aecmMode = EchoControlMobile::kSpeakerphone; 676 break; 677 case kAecmLoudSpeakerphone: 678 aecmMode = EchoControlMobile::kLoudSpeakerphone; 679 break; 680 } 681 682 683 if (_shared->audio_processing()->echo_control_mobile()-> 684 set_routing_mode(aecmMode) != 0) { 685 _shared->SetLastError(VE_APM_ERROR, kTraceError, 686 "SetAECMMode() failed to set AECM routing mode"); 687 return -1; 688 } 689 if (_shared->audio_processing()->echo_control_mobile()-> 690 enable_comfort_noise(enableCNG) != 0) { 691 _shared->SetLastError(VE_APM_ERROR, kTraceError, 692 "SetAECMMode() failed to set comfort noise state for AECM"); 693 return -1; 694 } 695 696 return 0; 697 #else 698 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 699 "SetAECMMode() EC is not supported"); 700 return -1; 701 #endif 702 } 703 704 int VoEAudioProcessingImpl::GetAecmMode(AecmModes& mode, bool& enabledCNG) { 705 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 706 "GetAECMMode(mode=?)"); 707 #ifdef WEBRTC_VOICE_ENGINE_ECHO 708 if (!_shared->statistics().Initialized()) { 709 _shared->SetLastError(VE_NOT_INITED, kTraceError); 710 return -1; 711 } 712 713 enabledCNG = false; 714 715 EchoControlMobile::RoutingMode aecmMode = 716 _shared->audio_processing()->echo_control_mobile()->routing_mode(); 717 enabledCNG = _shared->audio_processing()->echo_control_mobile()-> 718 is_comfort_noise_enabled(); 719 720 switch (aecmMode) { 721 case EchoControlMobile::kQuietEarpieceOrHeadset: 722 mode = kAecmQuietEarpieceOrHeadset; 723 break; 724 case EchoControlMobile::kEarpiece: 725 mode = kAecmEarpiece; 726 break; 727 case EchoControlMobile::kLoudEarpiece: 728 mode = kAecmLoudEarpiece; 729 break; 730 case EchoControlMobile::kSpeakerphone: 731 mode = kAecmSpeakerphone; 732 break; 733 case EchoControlMobile::kLoudSpeakerphone: 734 mode = kAecmLoudSpeakerphone; 735 break; 736 } 737 738 return 0; 739 #else 740 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 741 "GetAECMMode() EC is not supported"); 742 return -1; 743 #endif 744 } 745 746 int VoEAudioProcessingImpl::EnableHighPassFilter(bool enable) { 747 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 748 "EnableHighPassFilter(%d)", enable); 749 if (_shared->audio_processing()->high_pass_filter()->Enable(enable) != 750 AudioProcessing::kNoError) { 751 _shared->SetLastError(VE_APM_ERROR, kTraceError, 752 "HighPassFilter::Enable() failed."); 753 return -1; 754 } 755 756 return 0; 757 } 758 759 bool VoEAudioProcessingImpl::IsHighPassFilterEnabled() { 760 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 761 "IsHighPassFilterEnabled()"); 762 return _shared->audio_processing()->high_pass_filter()->is_enabled(); 763 } 764 765 int VoEAudioProcessingImpl::RegisterRxVadObserver( 766 int channel, 767 VoERxVadCallback& observer) { 768 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 769 "RegisterRxVadObserver()"); 770 if (!_shared->statistics().Initialized()) { 771 _shared->SetLastError(VE_NOT_INITED, kTraceError); 772 return -1; 773 } 774 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 775 voe::Channel* channelPtr = ch.channel(); 776 if (channelPtr == NULL) { 777 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 778 "RegisterRxVadObserver() failed to locate channel"); 779 return -1; 780 } 781 return channelPtr->RegisterRxVadObserver(observer); 782 } 783 784 int VoEAudioProcessingImpl::DeRegisterRxVadObserver(int channel) { 785 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 786 "DeRegisterRxVadObserver()"); 787 if (!_shared->statistics().Initialized()) { 788 _shared->SetLastError(VE_NOT_INITED, kTraceError); 789 return -1; 790 } 791 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 792 voe::Channel* channelPtr = ch.channel(); 793 if (channelPtr == NULL) { 794 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 795 "DeRegisterRxVadObserver() failed to locate channel"); 796 return -1; 797 } 798 799 return channelPtr->DeRegisterRxVadObserver(); 800 } 801 802 int VoEAudioProcessingImpl::VoiceActivityIndicator(int channel) { 803 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 804 "VoiceActivityIndicator(channel=%d)", channel); 805 if (!_shared->statistics().Initialized()) { 806 _shared->SetLastError(VE_NOT_INITED, kTraceError); 807 return -1; 808 } 809 810 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 811 voe::Channel* channelPtr = ch.channel(); 812 if (channelPtr == NULL) { 813 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 814 "DeRegisterRxVadObserver() failed to locate channel"); 815 return -1; 816 } 817 int activity(-1); 818 channelPtr->VoiceActivityIndicator(activity); 819 820 return activity; 821 } 822 823 int VoEAudioProcessingImpl::SetEcMetricsStatus(bool enable) { 824 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 825 "SetEcMetricsStatus(enable=%d)", enable); 826 #ifdef WEBRTC_VOICE_ENGINE_ECHO 827 if (!_shared->statistics().Initialized()) { 828 _shared->SetLastError(VE_NOT_INITED, kTraceError); 829 return -1; 830 } 831 832 if ((_shared->audio_processing()->echo_cancellation()->enable_metrics(enable) 833 != 0) || 834 (_shared->audio_processing()->echo_cancellation()->enable_delay_logging( 835 enable) != 0)) { 836 _shared->SetLastError(VE_APM_ERROR, kTraceError, 837 "SetEcMetricsStatus() unable to set EC metrics mode"); 838 return -1; 839 } 840 return 0; 841 #else 842 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 843 "SetEcStatus() EC is not supported"); 844 return -1; 845 #endif 846 } 847 848 int VoEAudioProcessingImpl::GetEcMetricsStatus(bool& enabled) { 849 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 850 "GetEcMetricsStatus(enabled=?)"); 851 #ifdef WEBRTC_VOICE_ENGINE_ECHO 852 if (!_shared->statistics().Initialized()) { 853 _shared->SetLastError(VE_NOT_INITED, kTraceError); 854 return -1; 855 } 856 857 bool echo_mode = 858 _shared->audio_processing()->echo_cancellation()->are_metrics_enabled(); 859 bool delay_mode = _shared->audio_processing()->echo_cancellation()-> 860 is_delay_logging_enabled(); 861 862 if (echo_mode != delay_mode) { 863 _shared->SetLastError(VE_APM_ERROR, kTraceError, 864 "GetEcMetricsStatus() delay logging and echo mode are not the same"); 865 return -1; 866 } 867 868 enabled = echo_mode; 869 870 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 871 "GetEcMetricsStatus() => enabled=%d", enabled); 872 return 0; 873 #else 874 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 875 "SetEcStatus() EC is not supported"); 876 return -1; 877 #endif 878 } 879 880 int VoEAudioProcessingImpl::GetEchoMetrics(int& ERL, 881 int& ERLE, 882 int& RERL, 883 int& A_NLP) { 884 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 885 "GetEchoMetrics(ERL=?, ERLE=?, RERL=?, A_NLP=?)"); 886 #ifdef WEBRTC_VOICE_ENGINE_ECHO 887 if (!_shared->statistics().Initialized()) { 888 _shared->SetLastError(VE_NOT_INITED, kTraceError); 889 return -1; 890 } 891 if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) { 892 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 893 "GetEchoMetrics() AudioProcessingModule AEC is not enabled"); 894 return -1; 895 } 896 897 // Get Echo Metrics from Audio Processing Module. 898 EchoCancellation::Metrics echoMetrics; 899 if (_shared->audio_processing()->echo_cancellation()->GetMetrics( 900 &echoMetrics)) { 901 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1), 902 "GetEchoMetrics(), AudioProcessingModule metrics error"); 903 return -1; 904 } 905 906 // Echo quality metrics. 907 ERL = echoMetrics.echo_return_loss.instant; 908 ERLE = echoMetrics.echo_return_loss_enhancement.instant; 909 RERL = echoMetrics.residual_echo_return_loss.instant; 910 A_NLP = echoMetrics.a_nlp.instant; 911 912 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 913 "GetEchoMetrics() => ERL=%d, ERLE=%d, RERL=%d, A_NLP=%d", 914 ERL, ERLE, RERL, A_NLP); 915 return 0; 916 #else 917 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 918 "SetEcStatus() EC is not supported"); 919 return -1; 920 #endif 921 } 922 923 int VoEAudioProcessingImpl::GetEcDelayMetrics(int& delay_median, 924 int& delay_std) { 925 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 926 "GetEcDelayMetrics(median=?, std=?)"); 927 #ifdef WEBRTC_VOICE_ENGINE_ECHO 928 if (!_shared->statistics().Initialized()) { 929 _shared->SetLastError(VE_NOT_INITED, kTraceError); 930 return -1; 931 } 932 if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) { 933 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 934 "GetEcDelayMetrics() AudioProcessingModule AEC is not enabled"); 935 return -1; 936 } 937 938 int median = 0; 939 int std = 0; 940 // Get delay-logging values from Audio Processing Module. 941 if (_shared->audio_processing()->echo_cancellation()->GetDelayMetrics( 942 &median, &std)) { 943 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1), 944 "GetEcDelayMetrics(), AudioProcessingModule delay-logging " 945 "error"); 946 return -1; 947 } 948 949 // EC delay-logging metrics 950 delay_median = median; 951 delay_std = std; 952 953 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 954 "GetEcDelayMetrics() => delay_median=%d, delay_std=%d", 955 delay_median, delay_std); 956 return 0; 957 #else 958 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 959 "SetEcStatus() EC is not supported"); 960 return -1; 961 #endif 962 } 963 964 int VoEAudioProcessingImpl::StartDebugRecording(const char* fileNameUTF8) { 965 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 966 "StartDebugRecording()"); 967 if (!_shared->statistics().Initialized()) { 968 _shared->SetLastError(VE_NOT_INITED, kTraceError); 969 return -1; 970 } 971 972 return _shared->audio_processing()->StartDebugRecording(fileNameUTF8); 973 } 974 975 int VoEAudioProcessingImpl::StartDebugRecording(FILE* file_handle) { 976 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 977 "StartDebugRecording()"); 978 if (!_shared->statistics().Initialized()) { 979 _shared->SetLastError(VE_NOT_INITED, kTraceError); 980 return -1; 981 } 982 983 return _shared->audio_processing()->StartDebugRecording(file_handle); 984 } 985 986 int VoEAudioProcessingImpl::StopDebugRecording() { 987 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 988 "StopDebugRecording()"); 989 if (!_shared->statistics().Initialized()) { 990 _shared->SetLastError(VE_NOT_INITED, kTraceError); 991 return -1; 992 } 993 994 return _shared->audio_processing()->StopDebugRecording(); 995 } 996 997 int VoEAudioProcessingImpl::SetTypingDetectionStatus(bool enable) { 998 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 999 "SetTypingDetectionStatus()"); 1000 #if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION) 1001 NOT_SUPPORTED(_shared->statistics()); 1002 #else 1003 if (!_shared->statistics().Initialized()) { 1004 _shared->SetLastError(VE_NOT_INITED, kTraceError); 1005 return -1; 1006 } 1007 1008 // Just use the VAD state to determine if we should enable typing detection 1009 // or not 1010 1011 if (_shared->audio_processing()->voice_detection()->Enable(enable)) { 1012 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 1013 "SetTypingDetectionStatus() failed to set VAD state"); 1014 return -1; 1015 } 1016 if (_shared->audio_processing()->voice_detection()->set_likelihood( 1017 VoiceDetection::kVeryLowLikelihood)) { 1018 _shared->SetLastError(VE_APM_ERROR, kTraceWarning, 1019 "SetTypingDetectionStatus() failed to set VAD likelihood to low"); 1020 return -1; 1021 } 1022 1023 return 0; 1024 #endif 1025 } 1026 1027 int VoEAudioProcessingImpl::GetTypingDetectionStatus(bool& enabled) { 1028 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 1029 "GetTypingDetectionStatus()"); 1030 if (!_shared->statistics().Initialized()) { 1031 _shared->SetLastError(VE_NOT_INITED, kTraceError); 1032 return -1; 1033 } 1034 // Just use the VAD state to determine if we should enable typing 1035 // detection or not 1036 1037 enabled = _shared->audio_processing()->voice_detection()->is_enabled(); 1038 1039 return 0; 1040 } 1041 1042 1043 int VoEAudioProcessingImpl::TimeSinceLastTyping(int &seconds) { 1044 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 1045 "TimeSinceLastTyping()"); 1046 #if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION) 1047 NOT_SUPPORTED(_shared->statistics()); 1048 #else 1049 if (!_shared->statistics().Initialized()) { 1050 _shared->SetLastError(VE_NOT_INITED, kTraceError); 1051 return -1; 1052 } 1053 // Check if typing detection is enabled 1054 bool enabled = _shared->audio_processing()->voice_detection()->is_enabled(); 1055 if (enabled) 1056 { 1057 _shared->transmit_mixer()->TimeSinceLastTyping(seconds); 1058 return 0; 1059 } 1060 else 1061 { 1062 _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, 1063 "SetTypingDetectionStatus is not enabled"); 1064 return -1; 1065 } 1066 #endif 1067 } 1068 1069 int VoEAudioProcessingImpl::SetTypingDetectionParameters(int timeWindow, 1070 int costPerTyping, 1071 int reportingThreshold, 1072 int penaltyDecay, 1073 int typeEventDelay) { 1074 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 1075 "SetTypingDetectionParameters()"); 1076 #if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION) 1077 NOT_SUPPORTED(_shared->statistics()); 1078 #else 1079 if (!_shared->statistics().Initialized()) { 1080 _shared->statistics().SetLastError(VE_NOT_INITED, kTraceError); 1081 return -1; 1082 } 1083 return (_shared->transmit_mixer()->SetTypingDetectionParameters(timeWindow, 1084 costPerTyping, reportingThreshold, penaltyDecay, typeEventDelay)); 1085 #endif 1086 } 1087 1088 void VoEAudioProcessingImpl::EnableStereoChannelSwapping(bool enable) { 1089 LOG_API1(enable); 1090 _shared->transmit_mixer()->EnableStereoChannelSwapping(enable); 1091 } 1092 1093 bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() { 1094 LOG_API0(); 1095 return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled(); 1096 } 1097 1098 #endif // #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API 1099 1100 } // namespace webrtc 1101