Add support for clock drift compensation.

Support clock drift compensation on Windows and add an API to allow
enabling dynamically.

BUG=issue773
TEST=unittest, trybots

Review URL: https://webrtc-codereview.appspot.com/744007

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2683 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andrew@webrtc.org 2012-08-29 02:13:12 +00:00
parent 954cf806d9
commit 55c0d4a683
5 changed files with 133 additions and 20 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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