diff options
author | andrew@webrtc.org <andrew@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2012-10-22 18:19:23 +0000 |
---|---|---|
committer | andrew@webrtc.org <andrew@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d> | 2012-10-22 18:19:23 +0000 |
commit | b015cbede88899f67a53fbbe581b02ce8e327949 (patch) | |
tree | 530a64a3cfdbbabacab974c183326517d49e761e /voice_engine/voe_audio_processing_impl.cc | |
download | webrtc-b015cbede88899f67a53fbbe581b02ce8e327949.tar.gz |
Move src/ -> webrtc/
TBR=niklas.enbom@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/915006
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@2963 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'voice_engine/voe_audio_processing_impl.cc')
-rw-r--r-- | voice_engine/voe_audio_processing_impl.cc | 1154 |
1 files changed, 1154 insertions, 0 deletions
diff --git a/voice_engine/voe_audio_processing_impl.cc b/voice_engine/voe_audio_processing_impl.cc new file mode 100644 index 00000000..63909709 --- /dev/null +++ b/voice_engine/voe_audio_processing_impl.cc @@ -0,0 +1,1154 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "voe_audio_processing_impl.h" + +#include "audio_processing.h" +#include "channel.h" +#include "critical_section_wrapper.h" +#include "trace.h" +#include "transmit_mixer.h" +#include "voe_errors.h" +#include "voice_engine_impl.h" + +// TODO(andrew): move to a common place. +#define WEBRTC_TRACE_VOICE_API() \ + do { \ + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, \ + VoEId(_shared->instance_id(), -1), __FUNCTION__); \ + } while (0) + +#define WEBRTC_VOICE_INIT_CHECK() \ + do { \ + if (!_shared->statistics().Initialized()) { \ + _shared->SetLastError(VE_NOT_INITED, kTraceError); \ + return -1; \ + } \ + } while (0) + +#define WEBRTC_VOICE_INIT_CHECK_BOOL() \ + do { \ + if (!_shared->statistics().Initialized()) { \ + _shared->SetLastError(VE_NOT_INITED, kTraceError); \ + return false; \ + } \ + } while (0) + + +namespace webrtc { + +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) +static const EcModes kDefaultEcMode = kEcAecm; +#else +static const EcModes kDefaultEcMode = kEcAec; +#endif + +VoEAudioProcessing* VoEAudioProcessing::GetInterface(VoiceEngine* voiceEngine) { +#ifndef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API + return NULL; +#else + if (NULL == voiceEngine) { + return NULL; + } + VoiceEngineImpl* s = reinterpret_cast<VoiceEngineImpl*>(voiceEngine); + s->AddRef(); + return s; +#endif +} + +#ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API +VoEAudioProcessingImpl::VoEAudioProcessingImpl(voe::SharedData* shared) + : _isAecMode(kDefaultEcMode == kEcAec), + _shared(shared) { + WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), + "VoEAudioProcessingImpl::VoEAudioProcessingImpl() - ctor"); +} + +VoEAudioProcessingImpl::~VoEAudioProcessingImpl() { + WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), + "VoEAudioProcessingImpl::~VoEAudioProcessingImpl() - dtor"); +} + +int VoEAudioProcessingImpl::SetNsStatus(bool enable, NsModes mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetNsStatus(enable=%d, mode=%d)", enable, mode); +#ifdef WEBRTC_VOICE_ENGINE_NR + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + NoiseSuppression::Level nsLevel( + (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_NS_DEFAULT_MODE); + switch (mode) { + case kNsDefault: + nsLevel = (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_NS_DEFAULT_MODE; + break; + case kNsUnchanged: + nsLevel = _shared->audio_processing()->noise_suppression()->level(); + break; + case kNsConference: + nsLevel = NoiseSuppression::kHigh; + break; + case kNsLowSuppression: + nsLevel = NoiseSuppression::kLow; + break; + case kNsModerateSuppression: + nsLevel = NoiseSuppression::kModerate; + break; + case kNsHighSuppression: + nsLevel = NoiseSuppression::kHigh; + break; + case kNsVeryHighSuppression: + nsLevel = NoiseSuppression::kVeryHigh; + break; + } + + if (_shared->audio_processing()->noise_suppression()-> + set_level(nsLevel) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetNsStatus() failed to set Ns mode"); + return -1; + } + if (_shared->audio_processing()->noise_suppression()->Enable(enable) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetNsStatus() failed to set Ns state"); + return -1; + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetNsStatus() Ns is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetNsStatus(bool& enabled, NsModes& mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetNsStatus(enabled=?, mode=?)"); +#ifdef WEBRTC_VOICE_ENGINE_NR + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + bool enable(false); + NoiseSuppression::Level nsLevel( + (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_NS_DEFAULT_MODE); + + enable = _shared->audio_processing()->noise_suppression()->is_enabled(); + nsLevel = _shared->audio_processing()->noise_suppression()->level(); + + enabled = enable; + + switch (nsLevel) { + case NoiseSuppression::kLow: + mode = kNsLowSuppression; + break; + case NoiseSuppression::kModerate: + mode = kNsModerateSuppression; + break; + case NoiseSuppression::kHigh: + mode = kNsHighSuppression; + break; + case NoiseSuppression::kVeryHigh: + mode = kNsVeryHighSuppression; + break; + } + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetNsStatus() => enabled=% d, mode=%d", enabled, mode); + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetNsStatus() Ns is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::SetAgcStatus(bool enable, AgcModes mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetAgcStatus(enable=%d, mode=%d)", enable, mode); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + +#if defined(WEBRTC_IOS) || defined(ATA) || defined(WEBRTC_ANDROID) + if (mode == kAgcAdaptiveAnalog) { + _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, + "SetAgcStatus() invalid Agc mode for mobile device"); + return -1; + } +#endif + + GainControl::Mode agcMode( + (GainControl::Mode)WEBRTC_VOICE_ENGINE_AGC_DEFAULT_MODE); + switch (mode) { + case kAgcDefault: + agcMode = (GainControl::Mode)WEBRTC_VOICE_ENGINE_AGC_DEFAULT_MODE; + break; + case kAgcUnchanged: + agcMode = _shared->audio_processing()->gain_control()->mode();; + break; + case kAgcFixedDigital: + agcMode = GainControl::kFixedDigital; + break; + case kAgcAdaptiveAnalog: + agcMode = GainControl::kAdaptiveAnalog; + break; + case kAgcAdaptiveDigital: + agcMode = GainControl::kAdaptiveDigital; + break; + } + + if (_shared->audio_processing()->gain_control()->set_mode(agcMode) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAgcStatus() failed to set Agc mode"); + return -1; + } + if (_shared->audio_processing()->gain_control()->Enable(enable) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAgcStatus() failed to set Agc state"); + return -1; + } + + if (agcMode != GainControl::kFixedDigital) { + // Set Agc state in the ADM when adaptive Agc mode has been selected. + // Note that we also enable the ADM Agc when Adaptive Digital mode is + // used since we want to be able to provide the APM with updated mic + // levels when the user modifies the mic level manually. + if (_shared->audio_device()->SetAGC(enable) != 0) { + _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, + kTraceWarning, "SetAgcStatus() failed to set Agc mode"); + } + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetAgcStatus() Agc is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetAgcStatus(bool& enabled, AgcModes& mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetAgcStatus(enabled=?, mode=?)"); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + bool enable(false); + GainControl::Mode agcMode( + (GainControl::Mode)WEBRTC_VOICE_ENGINE_AGC_DEFAULT_MODE); + + enable = _shared->audio_processing()->gain_control()->is_enabled(); + agcMode = _shared->audio_processing()->gain_control()->mode(); + + enabled = enable; + + switch (agcMode) { + case GainControl::kFixedDigital: + mode = kAgcFixedDigital; + break; + case GainControl::kAdaptiveAnalog: + mode = kAgcAdaptiveAnalog; + break; + case GainControl::kAdaptiveDigital: + mode = kAgcAdaptiveDigital; + break; + } + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetAgcStatus() => enabled=%d, mode=%d", enabled, mode); + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetAgcStatus() Agc is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::SetAgcConfig(const AgcConfig config) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetAgcConfig()"); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + if (_shared->audio_processing()->gain_control()->set_target_level_dbfs( + config.targetLeveldBOv) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAgcConfig() failed to set target peak |level|" + " (or envelope) of the Agc"); + return -1; + } + if (_shared->audio_processing()->gain_control()->set_compression_gain_db( + config.digitalCompressionGaindB) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAgcConfig() failed to set the range in |gain| " + "the digital compression stage may apply"); + return -1; + } + if (_shared->audio_processing()->gain_control()->enable_limiter( + config.limiterEnable) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAgcConfig() failed to set hard limiter to the signal"); + return -1; + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetAgcConfig() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetAgcConfig(AgcConfig& config) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetAgcConfig(config=?)"); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + config.targetLeveldBOv = + _shared->audio_processing()->gain_control()->target_level_dbfs(); + config.digitalCompressionGaindB = + _shared->audio_processing()->gain_control()->compression_gain_db(); + config.limiterEnable = + _shared->audio_processing()->gain_control()->is_limiter_enabled(); + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetAgcConfig() => targetLeveldBOv=%u, " + "digitalCompressionGaindB=%u, limiterEnable=%d", + config.targetLeveldBOv, + config.digitalCompressionGaindB, + config.limiterEnable); + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetAgcConfig() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::SetRxNsStatus(int channel, + bool enable, + NsModes mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetRxNsStatus(channel=%d, enable=%d, mode=%d)", + channel, (int)enable, (int)mode); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "SetRxNsStatus() failed to locate channel"); + return -1; + } + return channelPtr->SetRxNsStatus(enable, mode); +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetRxNsStatus() AGC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetRxNsStatus(int channel, + bool& enabled, + NsModes& mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetRxNsStatus(channel=%d, enable=?, mode=?)", channel); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "GetRxNsStatus() failed to locate channel"); + return -1; + } + return channelPtr->GetRxNsStatus(enabled, mode); +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetRxNsStatus() Agc is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::SetRxAgcStatus(int channel, + bool enable, + AgcModes mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetRxAgcStatus(channel=%d, enable=%d, mode=%d)", + channel, (int)enable, (int)mode); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "SetRxAgcStatus() failed to locate channel"); + return -1; + } + return channelPtr->SetRxAgcStatus(enable, mode); +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetRxAgcStatus() Agc is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetRxAgcStatus(int channel, + bool& enabled, + AgcModes& mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetRxAgcStatus(channel=%d, enable=?, mode=?)", channel); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "GetRxAgcStatus() failed to locate channel"); + return -1; + } + return channelPtr->GetRxAgcStatus(enabled, mode); +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetRxAgcStatus() Agc is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::SetRxAgcConfig(int channel, + const AgcConfig config) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetRxAgcConfig(channel=%d)", channel); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "SetRxAgcConfig() failed to locate channel"); + return -1; + } + return channelPtr->SetRxAgcConfig(config); +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetRxAgcConfig() Agc is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetRxAgcConfig(int channel, AgcConfig& config) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetRxAgcConfig(channel=%d)", channel); +#ifdef WEBRTC_VOICE_ENGINE_AGC + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "GetRxAgcConfig() failed to locate channel"); + return -1; + } + return channelPtr->GetRxAgcConfig(config); +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetRxAgcConfig() Agc is not supported"); + return -1; +#endif +} + +bool VoEAudioProcessing::DriftCompensationSupported() { +#if defined(WEBRTC_DRIFT_COMPENSATION_SUPPORTED) + return true; +#else + return false; +#endif +} + +int VoEAudioProcessingImpl::EnableDriftCompensation(bool enable) { + WEBRTC_TRACE_VOICE_API(); + WEBRTC_VOICE_INIT_CHECK(); + + if (!DriftCompensationSupported()) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "Drift compensation is not supported on this platform."); + return -1; + } + + EchoCancellation* aec = _shared->audio_processing()->echo_cancellation(); + if (aec->enable_drift_compensation(enable) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "aec->enable_drift_compensation() failed"); + return -1; + } + return 0; +} + +bool VoEAudioProcessingImpl::DriftCompensationEnabled() { + WEBRTC_TRACE_VOICE_API(); + WEBRTC_VOICE_INIT_CHECK_BOOL(); + + EchoCancellation* aec = _shared->audio_processing()->echo_cancellation(); + return aec->is_drift_compensation_enabled(); +} + +int VoEAudioProcessingImpl::SetEcStatus(bool enable, EcModes mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetEcStatus(enable=%d, mode=%d)", enable, mode); +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + // AEC mode + if ((mode == kEcDefault) || + (mode == kEcConference) || + (mode == kEcAec) || + ((mode == kEcUnchanged) && + (_isAecMode == true))) { + if (enable) { + // Disable the AECM before enable the AEC + if (_shared->audio_processing()->echo_control_mobile()->is_enabled()) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "SetEcStatus() disable AECM before enabling AEC"); + if (_shared->audio_processing()->echo_control_mobile()-> + Enable(false) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcStatus() failed to disable AECM"); + return -1; + } + } + } + if (_shared->audio_processing()->echo_cancellation()->Enable(enable) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcStatus() failed to set AEC state"); + return -1; + } + if (mode == kEcConference) { + if (_shared->audio_processing()->echo_cancellation()-> + set_suppression_level(EchoCancellation::kHighSuppression) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcStatus() failed to set aggressiveness to high"); + return -1; + } + } else { + if (_shared->audio_processing()->echo_cancellation()-> + set_suppression_level( + EchoCancellation::kModerateSuppression) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcStatus() failed to set aggressiveness to moderate"); + return -1; + } + } + + _isAecMode = true; + } else if ((mode == kEcAecm) || + ((mode == kEcUnchanged) && + (_isAecMode == false))) { + if (enable) { + // Disable the AEC before enable the AECM + if (_shared->audio_processing()->echo_cancellation()->is_enabled()) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "SetEcStatus() disable AEC before enabling AECM"); + if (_shared->audio_processing()->echo_cancellation()-> + Enable(false) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcStatus() failed to disable AEC"); + return -1; + } + } + } + if (_shared->audio_processing()->echo_control_mobile()-> + Enable(enable) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcStatus() failed to set AECM state"); + return -1; + } + _isAecMode = false; + } else { + _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError, + "SetEcStatus() invalid EC mode"); + return -1; + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetEcStatus() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetEcStatus(bool& enabled, EcModes& mode) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcStatus()"); +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + if (_isAecMode == true) { + mode = kEcAec; + enabled = _shared->audio_processing()->echo_cancellation()->is_enabled(); + } else { + mode = kEcAecm; + enabled = _shared->audio_processing()->echo_control_mobile()-> + is_enabled(); + } + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcStatus() => enabled=%i, mode=%i", + enabled, (int)mode); + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetEcStatus() EC is not supported"); + return -1; +#endif +} + +void VoEAudioProcessingImpl::SetDelayOffsetMs(int offset) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetDelayOffsetMs(offset = %d)", offset); + _shared->audio_processing()->set_delay_offset_ms(offset); +} + +int VoEAudioProcessingImpl::DelayOffsetMs() { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "DelayOffsetMs()"); + return _shared->audio_processing()->delay_offset_ms(); +} + +int VoEAudioProcessingImpl::SetAecmMode(AecmModes mode, bool enableCNG) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetAECMMode(mode = %d)", mode); +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + EchoControlMobile::RoutingMode aecmMode( + EchoControlMobile::kQuietEarpieceOrHeadset); + + switch (mode) { + case kAecmQuietEarpieceOrHeadset: + aecmMode = EchoControlMobile::kQuietEarpieceOrHeadset; + break; + case kAecmEarpiece: + aecmMode = EchoControlMobile::kEarpiece; + break; + case kAecmLoudEarpiece: + aecmMode = EchoControlMobile::kLoudEarpiece; + break; + case kAecmSpeakerphone: + aecmMode = EchoControlMobile::kSpeakerphone; + break; + case kAecmLoudSpeakerphone: + aecmMode = EchoControlMobile::kLoudSpeakerphone; + break; + } + + + if (_shared->audio_processing()->echo_control_mobile()-> + set_routing_mode(aecmMode) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAECMMode() failed to set AECM routing mode"); + return -1; + } + if (_shared->audio_processing()->echo_control_mobile()-> + enable_comfort_noise(enableCNG) != 0) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetAECMMode() failed to set comfort noise state for AECM"); + return -1; + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetAECMMode() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetAecmMode(AecmModes& mode, bool& enabledCNG) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetAECMMode(mode=?)"); +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + enabledCNG = false; + + EchoControlMobile::RoutingMode aecmMode = + _shared->audio_processing()->echo_control_mobile()->routing_mode(); + enabledCNG = _shared->audio_processing()->echo_control_mobile()-> + is_comfort_noise_enabled(); + + switch (aecmMode) { + case EchoControlMobile::kQuietEarpieceOrHeadset: + mode = kAecmQuietEarpieceOrHeadset; + break; + case EchoControlMobile::kEarpiece: + mode = kAecmEarpiece; + break; + case EchoControlMobile::kLoudEarpiece: + mode = kAecmLoudEarpiece; + break; + case EchoControlMobile::kSpeakerphone: + mode = kAecmSpeakerphone; + break; + case EchoControlMobile::kLoudSpeakerphone: + mode = kAecmLoudSpeakerphone; + break; + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "GetAECMMode() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::EnableHighPassFilter(bool enable) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "EnableHighPassFilter(%d)", enable); + if (_shared->audio_processing()->high_pass_filter()->Enable(enable) != + AudioProcessing::kNoError) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "HighPassFilter::Enable() failed."); + return -1; + } + + return 0; +} + +bool VoEAudioProcessingImpl::IsHighPassFilterEnabled() { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "IsHighPassFilterEnabled()"); + return _shared->audio_processing()->high_pass_filter()->is_enabled(); +} + +int VoEAudioProcessingImpl::RegisterRxVadObserver( + int channel, + VoERxVadCallback& observer) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "RegisterRxVadObserver()"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "RegisterRxVadObserver() failed to locate channel"); + return -1; + } + return channelPtr->RegisterRxVadObserver(observer); +} + +int VoEAudioProcessingImpl::DeRegisterRxVadObserver(int channel) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "DeRegisterRxVadObserver()"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "DeRegisterRxVadObserver() failed to locate channel"); + return -1; + } + + return channelPtr->DeRegisterRxVadObserver(); +} + +int VoEAudioProcessingImpl::VoiceActivityIndicator(int channel) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "VoiceActivityIndicator(channel=%d)", channel); + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + voe::ScopedChannel sc(_shared->channel_manager(), channel); + voe::Channel* channelPtr = sc.ChannelPtr(); + if (channelPtr == NULL) { + _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, + "DeRegisterRxVadObserver() failed to locate channel"); + return -1; + } + int activity(-1); + channelPtr->VoiceActivityIndicator(activity); + + return activity; +} + +int VoEAudioProcessingImpl::SetEcMetricsStatus(bool enable) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetEcMetricsStatus(enable=%d)", enable); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + if ((_shared->audio_processing()->echo_cancellation()->enable_metrics(enable) + != 0) || + (_shared->audio_processing()->echo_cancellation()->enable_delay_logging( + enable) != 0)) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "SetEcMetricsStatus() unable to set EC metrics mode"); + return -1; + } + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetEcStatus() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetEcMetricsStatus(bool& enabled) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcMetricsStatus(enabled=?)"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + bool echo_mode = + _shared->audio_processing()->echo_cancellation()->are_metrics_enabled(); + bool delay_mode = _shared->audio_processing()->echo_cancellation()-> + is_delay_logging_enabled(); + + if (echo_mode != delay_mode) { + _shared->SetLastError(VE_APM_ERROR, kTraceError, + "GetEcMetricsStatus() delay logging and echo mode are not the same"); + return -1; + } + + enabled = echo_mode; + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcMetricsStatus() => enabled=%d", enabled); + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetEcStatus() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetEchoMetrics(int& ERL, + int& ERLE, + int& RERL, + int& A_NLP) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEchoMetrics(ERL=?, ERLE=?, RERL=?, A_NLP=?)"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "GetEchoMetrics() AudioProcessingModule AEC is not enabled"); + return -1; + } + + // Get Echo Metrics from Audio Processing Module. + EchoCancellation::Metrics echoMetrics; + if (_shared->audio_processing()->echo_cancellation()->GetMetrics( + &echoMetrics)) { + WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEchoMetrics(), AudioProcessingModule metrics error"); + return -1; + } + + // Echo quality metrics. + ERL = echoMetrics.echo_return_loss.instant; + ERLE = echoMetrics.echo_return_loss_enhancement.instant; + RERL = echoMetrics.residual_echo_return_loss.instant; + A_NLP = echoMetrics.a_nlp.instant; + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEchoMetrics() => ERL=%d, ERLE=%d, RERL=%d, A_NLP=%d", + ERL, ERLE, RERL, A_NLP); + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetEcStatus() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetEcDelayMetrics(int& delay_median, + int& delay_std) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcDelayMetrics(median=?, std=?)"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + if (!_shared->audio_processing()->echo_cancellation()->is_enabled()) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "GetEcDelayMetrics() AudioProcessingModule AEC is not enabled"); + return -1; + } + + int median = 0; + int std = 0; + // Get delay-logging values from Audio Processing Module. + if (_shared->audio_processing()->echo_cancellation()->GetDelayMetrics( + &median, &std)) { + WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcDelayMetrics(), AudioProcessingModule delay-logging " + "error"); + return -1; + } + + // EC delay-logging metrics + delay_median = median; + delay_std = std; + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetEcDelayMetrics() => delay_median=%d, delay_std=%d", + delay_median, delay_std); + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetEcStatus() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::StartDebugRecording(const char* fileNameUTF8) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "StartDebugRecording()"); + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + return _shared->audio_processing()->StartDebugRecording(fileNameUTF8); + +} + +int VoEAudioProcessingImpl::StopDebugRecording() { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "StopDebugRecording()"); + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + return _shared->audio_processing()->StopDebugRecording(); +} + +int VoEAudioProcessingImpl::SetTypingDetectionStatus(bool enable) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetTypingDetectionStatus()"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); +#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + + // Just use the VAD state to determine if we should enable typing detection + // or not + + if (_shared->audio_processing()->voice_detection()->Enable(enable)) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "SetTypingDetectionStatus() failed to set VAD state"); + return -1; + } + if (_shared->audio_processing()->voice_detection()->set_likelihood( + VoiceDetection::kVeryLowLikelihood)) { + _shared->SetLastError(VE_APM_ERROR, kTraceWarning, + "SetTypingDetectionStatus() failed to set VAD likelihood to low"); + return -1; + } + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetTypingDetectionStatus is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetTypingDetectionStatus(bool& enabled) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "GetTypingDetectionStatus()"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + // Just use the VAD state to determine if we should enable typing + // detection or not + + enabled = _shared->audio_processing()->voice_detection()->is_enabled(); + + return 0; +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetTypingDetectionStatus is not supported"); + return -1; +#endif +} + + +int VoEAudioProcessingImpl::TimeSinceLastTyping(int &seconds) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "TimeSinceLastTyping()"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION + if (!_shared->statistics().Initialized()) { + _shared->SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + // Check if typing detection is enabled + bool enabled = _shared->audio_processing()->voice_detection()->is_enabled(); + if (enabled) + { + _shared->transmit_mixer()->TimeSinceLastTyping(seconds); + return 0; + } + else + { + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetTypingDetectionStatus is not enabled"); + return -1; + } +#else + _shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetTypingDetectionStatus is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::SetTypingDetectionParameters(int timeWindow, + int costPerTyping, + int reportingThreshold, + int penaltyDecay, + int typeEventDelay) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "SetTypingDetectionParameters()"); + ANDROID_NOT_SUPPORTED(_shared->statistics()); + IPHONE_NOT_SUPPORTED(_shared->statistics()); + +#ifdef WEBRTC_VOICE_ENGINE_TYPING_DETECTION + if (!_shared->statistics().Initialized()) { + _shared->statistics().SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + return (_shared->transmit_mixer()->SetTypingDetectionParameters(timeWindow, + costPerTyping, reportingThreshold, penaltyDecay, typeEventDelay)); + +#else + _shared->statistics().SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError, + "SetTypingDetectionParameters is not supported"); + return -1; +#endif + +} + +void VoEAudioProcessingImpl::EnableStereoChannelSwapping(bool enable) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), + "EnableStereoChannelSwapping(enable=%d)", enable); + _shared->transmit_mixer()->EnableStereoChannelSwapping(enable); +} + +bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() { + WEBRTC_TRACE_VOICE_API(); + return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled(); +} + +#endif // #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API + +} // namespace webrtc |