1047 lines
34 KiB
C++
1047 lines
34 KiB
C++
|
/*
|
||
|
* 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 "webrtc/voice_engine/voe_audio_processing_impl.h"
|
||
|
|
||
|
#include "webrtc/base/logging.h"
|
||
|
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||
|
#include "webrtc/system_wrappers/include/trace.h"
|
||
|
#include "webrtc/voice_engine/channel.h"
|
||
|
#include "webrtc/voice_engine/include/voe_errors.h"
|
||
|
#include "webrtc/voice_engine/transmit_mixer.h"
|
||
|
#include "webrtc/voice_engine/voice_engine_impl.h"
|
||
|
|
||
|
// TODO(andrew): move to a common place.
|
||
|
#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 = static_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 = kDefaultNsMode;
|
||
|
switch (mode) {
|
||
|
case kNsDefault:
|
||
|
nsLevel = kDefaultNsMode;
|
||
|
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) {
|
||
|
#ifdef WEBRTC_VOICE_ENGINE_NR
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
enabled = _shared->audio_processing()->noise_suppression()->is_enabled();
|
||
|
NoiseSuppression::Level nsLevel =
|
||
|
_shared->audio_processing()->noise_suppression()->level();
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
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 = kDefaultAgcMode;
|
||
|
switch (mode) {
|
||
|
case kAgcDefault:
|
||
|
agcMode = kDefaultAgcMode;
|
||
|
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) {
|
||
|
#ifdef WEBRTC_VOICE_ENGINE_AGC
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
enabled = _shared->audio_processing()->gain_control()->is_enabled();
|
||
|
GainControl::Mode agcMode =
|
||
|
_shared->audio_processing()->gain_control()->mode();
|
||
|
|
||
|
switch (agcMode) {
|
||
|
case GainControl::kFixedDigital:
|
||
|
mode = kAgcFixedDigital;
|
||
|
break;
|
||
|
case GainControl::kAdaptiveAnalog:
|
||
|
mode = kAgcAdaptiveAnalog;
|
||
|
break;
|
||
|
case GainControl::kAdaptiveDigital:
|
||
|
mode = kAgcAdaptiveDigital;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
#else
|
||
|
_shared->SetLastError(VE_FUNC_NOT_SUPPORTED, kTraceError,
|
||
|
"GetAgcStatus() Agc is not supported");
|
||
|
return -1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int VoEAudioProcessingImpl::SetAgcConfig(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) {
|
||
|
#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();
|
||
|
|
||
|
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) {
|
||
|
#ifdef WEBRTC_VOICE_ENGINE_NR
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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() NS is not supported");
|
||
|
return -1;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int VoEAudioProcessingImpl::GetRxNsStatus(int channel,
|
||
|
bool& enabled,
|
||
|
NsModes& mode) {
|
||
|
#ifdef WEBRTC_VOICE_ENGINE_NR
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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() NS 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::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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) {
|
||
|
#ifdef WEBRTC_VOICE_ENGINE_AGC
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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, 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::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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) {
|
||
|
#ifdef WEBRTC_VOICE_ENGINE_AGC
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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_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_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) {
|
||
|
#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();
|
||
|
}
|
||
|
|
||
|
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() {
|
||
|
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) {
|
||
|
#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() {
|
||
|
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()");
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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()");
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
||
|
voe::Channel* channelPtr = ch.channel();
|
||
|
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);
|
||
|
#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) {
|
||
|
#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;
|
||
|
|
||
|
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) {
|
||
|
#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;
|
||
|
|
||
|
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,
|
||
|
float& fraction_poor_delays) {
|
||
|
#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;
|
||
|
float poor_fraction = 0;
|
||
|
// Get delay-logging values from Audio Processing Module.
|
||
|
if (_shared->audio_processing()->echo_cancellation()->GetDelayMetrics(
|
||
|
&median, &std, &poor_fraction)) {
|
||
|
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;
|
||
|
fraction_poor_delays = poor_fraction;
|
||
|
|
||
|
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, -1);
|
||
|
}
|
||
|
|
||
|
int VoEAudioProcessingImpl::StartDebugRecording(FILE* file_handle) {
|
||
|
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(file_handle, -1);
|
||
|
}
|
||
|
|
||
|
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()");
|
||
|
#if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
|
||
|
NOT_SUPPORTED(_shared->statistics());
|
||
|
#else
|
||
|
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;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int VoEAudioProcessingImpl::GetTypingDetectionStatus(bool& enabled) {
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
int VoEAudioProcessingImpl::TimeSinceLastTyping(int& seconds) {
|
||
|
#if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
|
||
|
NOT_SUPPORTED(_shared->statistics());
|
||
|
#else
|
||
|
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;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int VoEAudioProcessingImpl::SetTypingDetectionParameters(int timeWindow,
|
||
|
int costPerTyping,
|
||
|
int reportingThreshold,
|
||
|
int penaltyDecay,
|
||
|
int typeEventDelay) {
|
||
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
||
|
"SetTypingDetectionParameters()");
|
||
|
#if !defined(WEBRTC_VOICE_ENGINE_TYPING_DETECTION)
|
||
|
NOT_SUPPORTED(_shared->statistics());
|
||
|
#else
|
||
|
if (!_shared->statistics().Initialized()) {
|
||
|
_shared->statistics().SetLastError(VE_NOT_INITED, kTraceError);
|
||
|
return -1;
|
||
|
}
|
||
|
return (_shared->transmit_mixer()->SetTypingDetectionParameters(
|
||
|
timeWindow, costPerTyping, reportingThreshold, penaltyDecay,
|
||
|
typeEventDelay));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void VoEAudioProcessingImpl::EnableStereoChannelSwapping(bool enable) {
|
||
|
_shared->transmit_mixer()->EnableStereoChannelSwapping(enable);
|
||
|
}
|
||
|
|
||
|
bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() {
|
||
|
return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled();
|
||
|
}
|
||
|
|
||
|
#endif // #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API
|
||
|
|
||
|
} // namespace webrtc
|