diff --git a/src/voice_engine/include/voe_audio_processing.h b/src/voice_engine/include/voe_audio_processing.h index 0e014877c2..4965d331bd 100644 --- a/src/voice_engine/include/voe_audio_processing.h +++ b/src/voice_engine/include/voe_audio_processing.h @@ -97,6 +97,15 @@ public: // Gets the EC status and mode. virtual int GetEcStatus(bool& enabled, EcModes& mode) = 0; + // Enables the compensation of clock drift between the capture and render + // streams by the echo canceller (i.e. only using EcMode==kEcAec). It will + // only be enabled if supported on the current platform; otherwise an error + // will be returned. Check if the platform is supported by calling + // |DriftCompensationSupported()|. + virtual int EnableDriftCompensation(bool enable) = 0; + virtual bool DriftCompensationEnabled() = 0; + static bool DriftCompensationSupported(); + // Sets a delay |offset| in ms to add to the system delay reported by the // OS, which is used by the AEC to synchronize far- and near-end streams. // In some cases a system may introduce a delay which goes unreported by the diff --git a/src/voice_engine/voe_audio_processing_impl.cc b/src/voice_engine/voe_audio_processing_impl.cc index 91a4a86de1..3012687785 100644 --- a/src/voice_engine/voe_audio_processing_impl.cc +++ b/src/voice_engine/voe_audio_processing_impl.cc @@ -25,6 +25,23 @@ 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(MAC_IPHONE) || defined(MAC_IPHONE_SIM) @@ -48,7 +65,8 @@ VoEAudioProcessing* VoEAudioProcessing::GetInterface(VoiceEngine* voiceEngine) { #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API VoEAudioProcessingImpl::VoEAudioProcessingImpl(voe::SharedData* shared) - : _isAecMode(kDefaultEcMode == kEcAec), _shared(shared) { + : _isAecMode(kDefaultEcMode == kEcAec), + _shared(shared) { WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), "VoEAudioProcessingImpl::VoEAudioProcessingImpl() - ctor"); } @@ -487,6 +505,41 @@ int VoEAudioProcessingImpl::GetRxAgcConfig(int channel, AgcConfig& config) { #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); @@ -520,21 +573,6 @@ int VoEAudioProcessingImpl::SetEcStatus(bool enable, EcModes mode) { "SetEcStatus() failed to set AEC state"); return -1; } -#ifdef CLOCK_SKEW_COMP - if (_shared->audio_processing()->echo_cancellation()-> - enable_drift_compensation(true) != 0) { - _shared->SetLastError(VE_APM_ERROR, kTraceError, - "SetEcStatus() failed to enable drift compensation"); - return -1; - } -#else - if (_shared->audio_processing()->echo_cancellation()-> - enable_drift_compensation(false) != 0) { - _shared->SetLastError(VE_APM_ERROR, kTraceError, - "SetEcStatus() failed to disable drift compensation"); - return -1; - } -#endif if (mode == kEcConference) { if (_shared->audio_processing()->echo_cancellation()-> set_suppression_level(EchoCancellation::kHighSuppression) != 0) { @@ -1111,8 +1149,6 @@ bool VoEAudioProcessingImpl::IsStereoChannelSwappingEnabled() { return _shared->transmit_mixer()->IsStereoChannelSwappingEnabled(); } - - #endif // #ifdef WEBRTC_VOICE_ENGINE_AUDIO_PROCESSING_API } // namespace webrtc diff --git a/src/voice_engine/voe_audio_processing_impl.h b/src/voice_engine/voe_audio_processing_impl.h index a4e7e2203b..3d6b64de7f 100644 --- a/src/voice_engine/voe_audio_processing_impl.h +++ b/src/voice_engine/voe_audio_processing_impl.h @@ -48,11 +48,11 @@ class VoEAudioProcessingImpl : public VoEAudioProcessing { virtual int GetRxAgcConfig(int channel, AgcConfig& config); virtual int SetEcStatus(bool enable, EcModes mode = kEcUnchanged); - virtual int GetEcStatus(bool& enabled, EcModes& mode); + virtual int EnableDriftCompensation(bool enable); + virtual bool DriftCompensationEnabled(); virtual void SetDelayOffsetMs(int offset); - virtual int DelayOffsetMs(); virtual int SetAecmMode(AecmModes mode = kAecmSpeakerphone, diff --git a/src/voice_engine/voe_audio_processing_unittest.cc b/src/voice_engine/voe_audio_processing_unittest.cc new file mode 100644 index 0000000000..1b4cec63cb --- /dev/null +++ b/src/voice_engine/voe_audio_processing_unittest.cc @@ -0,0 +1,64 @@ +/* + * 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 "voice_engine/include/voe_audio_processing.h" + +#include "gtest/gtest.h" +#include "voice_engine/include/voe_base.h" + +namespace webrtc { +namespace voe { +namespace { + +class VoEAudioProcessingTest : public ::testing::Test { + protected: + VoEAudioProcessingTest() + : voe_(VoiceEngine::Create()), + base_(VoEBase::GetInterface(voe_)), + audioproc_(VoEAudioProcessing::GetInterface(voe_)) { + } + + virtual ~VoEAudioProcessingTest() { + audioproc_->Release(); + base_->Release(); + VoiceEngine::Delete(voe_); + } + + VoiceEngine* voe_; + VoEBase* base_; + VoEAudioProcessing* audioproc_; +}; + +TEST_F(VoEAudioProcessingTest, FailureIfNotInitialized) { + EXPECT_EQ(-1, audioproc_->EnableDriftCompensation(true)); + EXPECT_EQ(-1, audioproc_->EnableDriftCompensation(false)); + EXPECT_FALSE(audioproc_->DriftCompensationEnabled()); +} + +// TODO(andrew): Ideally, DriftCompensationSupported() would be mocked for this. +TEST_F(VoEAudioProcessingTest, DriftCompensationIsEnabledIfSupported) { + ASSERT_EQ(0, base_->Init()); + bool supported = VoEAudioProcessing::DriftCompensationSupported(); + if (supported) { + EXPECT_EQ(0, audioproc_->EnableDriftCompensation(true)); + EXPECT_TRUE(audioproc_->DriftCompensationEnabled()); + EXPECT_EQ(0, audioproc_->EnableDriftCompensation(false)); + EXPECT_FALSE(audioproc_->DriftCompensationEnabled()); + } else { + EXPECT_EQ(-1, audioproc_->EnableDriftCompensation(true)); + EXPECT_FALSE(audioproc_->DriftCompensationEnabled()); + EXPECT_EQ(-1, audioproc_->EnableDriftCompensation(false)); + EXPECT_FALSE(audioproc_->DriftCompensationEnabled()); + } +} + +} // namespace +} // namespace voe +} // namespace webrtc diff --git a/src/voice_engine/voice_engine_core.gypi b/src/voice_engine/voice_engine_core.gypi index 4825072834..354993a3d3 100644 --- a/src/voice_engine/voice_engine_core.gypi +++ b/src/voice_engine/voice_engine_core.gypi @@ -118,6 +118,9 @@ }, ], 'conditions': [ + ['OS=="win"', { + 'defines': ['WEBRTC_DRIFT_COMPENSATION_SUPPORTED',], + }], ['include_tests==1', { 'targets': [ { @@ -146,6 +149,7 @@ 'sources': [ 'channel_unittest.cc', 'output_mixer_unittest.cc', + 'voe_audio_processing_unittest.cc', ], }, ], # targets