Remove usage of VoEAudioProcessing from WVoE/MC.

Calling APM and TransmitMixer directly instead.

BUG=webrtc:4690
TBR=peah@webrtc.org

Review-Url: https://codereview.webrtc.org/2681033010
Cr-Commit-Position: refs/heads/master@{#16734}
This commit is contained in:
solenberg 2017-02-21 00:54:31 -08:00 committed by Commit bot
parent 11c9eafc69
commit 76377c55b7
16 changed files with 760 additions and 445 deletions

View File

@ -101,6 +101,8 @@ rtc_static_library("rtc_media") {
libs = []
deps = []
sources = [
"engine/apm_helpers.cc",
"engine/apm_helpers.h",
"engine/internaldecoderfactory.cc",
"engine/internaldecoderfactory.h",
"engine/internalencoderfactory.cc",
@ -319,6 +321,7 @@ if (rtc_include_tests) {
"base/videocapturer_unittest.cc",
"base/videocommon_unittest.cc",
"base/videoengine_unittest.h",
"engine/apm_helpers_unittest.cc",
"engine/internaldecoderfactory_unittest.cc",
"engine/nullwebrtcvideoengine_unittest.cc",
"engine/payload_type_mapper_unittest.cc",

View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 2017 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/media/engine/apm_helpers.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/audio_device/include/audio_device.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/voice_engine/transmit_mixer.h"
namespace webrtc {
namespace apm_helpers {
AgcConfig GetAgcConfig(AudioProcessing* apm) {
RTC_DCHECK(apm);
AgcConfig result;
result.targetLeveldBOv = apm->gain_control()->target_level_dbfs();
result.digitalCompressionGaindB = apm->gain_control()->compression_gain_db();
result.limiterEnable = apm->gain_control()->is_limiter_enabled();
return result;
}
void SetAgcConfig(AudioProcessing* apm,
const AgcConfig& config) {
RTC_DCHECK(apm);
GainControl* gc = apm->gain_control();
if (gc->set_target_level_dbfs(config.targetLeveldBOv) != 0) {
LOG(LS_ERROR) << "Failed to set target level: " << config.targetLeveldBOv;
}
if (gc->set_compression_gain_db(config.digitalCompressionGaindB) != 0) {
LOG(LS_ERROR) << "Failed to set compression gain: "
<< config.digitalCompressionGaindB;
}
if (gc->enable_limiter(config.limiterEnable) != 0) {
LOG(LS_ERROR) << "Failed to set limiter on/off: " << config.limiterEnable;
}
}
void SetAgcStatus(AudioProcessing* apm,
AudioDeviceModule* adm,
bool enable,
AgcModes mode) {
RTC_DCHECK(apm);
RTC_DCHECK(adm);
#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
RTC_DCHECK_EQ(kAgcFixedDigital, mode);
GainControl::Mode agc_mode = GainControl::kFixedDigital;
#else
RTC_DCHECK_EQ(kAgcAdaptiveAnalog, mode);
GainControl::Mode agc_mode = GainControl::kAdaptiveAnalog;
#endif
GainControl* gc = apm->gain_control();
if (gc->set_mode(agc_mode) != 0) {
LOG(LS_ERROR) << "Failed to set AGC mode: " << agc_mode;
return;
}
if (gc->Enable(enable) != 0) {
LOG(LS_ERROR) << "Failed to enable/disable AGC: " << enable;
return;
}
// Set AGC state in the ADM when adaptive AGC mode has been selected.
if (adm->SetAGC(enable && agc_mode == GainControl::kAdaptiveAnalog) != 0) {
LOG(LS_ERROR) << "Failed to set AGC mode in ADM: " << enable;
return;
}
LOG(LS_INFO) << "AGC set to " << enable << " with mode " << mode;
}
void SetEcStatus(AudioProcessing* apm,
bool enable,
EcModes mode) {
RTC_DCHECK(apm);
RTC_DCHECK(mode == kEcConference || mode == kEcAecm) << "mode: " << mode;
EchoCancellation* ec = apm->echo_cancellation();
EchoControlMobile* ecm = apm->echo_control_mobile();
if (mode == kEcConference) {
// Disable the AECM before enabling the AEC.
if (enable && ecm->is_enabled() && ecm->Enable(false) != 0) {
LOG(LS_ERROR) << "Failed to disable AECM.";
return;
}
if (ec->Enable(enable) != 0) {
LOG(LS_ERROR) << "Failed to enable/disable AEC: " << enable;
return;
}
if (ec->set_suppression_level(EchoCancellation::kHighSuppression)
!= 0) {
LOG(LS_ERROR) << "Failed to set high AEC aggressiveness.";
return;
}
} else {
// Disable the AEC before enabling the AECM.
if (enable && ec->is_enabled() && ec->Enable(false) != 0) {
LOG(LS_ERROR) << "Failed to disable AEC.";
return;
}
if (ecm->Enable(enable) != 0) {
LOG(LS_ERROR) << "Failed to enable/disable AECM: " << enable;
return;
}
}
LOG(LS_INFO) << "Echo control set to " << enable << " with mode " << mode;
}
void SetEcMetricsStatus(AudioProcessing* apm, bool enable) {
RTC_DCHECK(apm);
if ((apm->echo_cancellation()->enable_metrics(enable) != 0) ||
(apm->echo_cancellation()->enable_delay_logging(enable) != 0)) {
LOG(LS_ERROR) << "Failed to enable/disable EC metrics: " << enable;
return;
}
LOG(LS_INFO) << "EC metrics set to " << enable;
}
void SetAecmMode(AudioProcessing* apm, bool enable) {
RTC_DCHECK(apm);
EchoControlMobile* ecm = apm->echo_control_mobile();
RTC_DCHECK_EQ(EchoControlMobile::kSpeakerphone, ecm->routing_mode());
if (ecm->enable_comfort_noise(enable) != 0) {
LOG(LS_ERROR) << "Failed to enable/disable CNG: " << enable;
return;
}
LOG(LS_INFO) << "CNG set to " << enable;
}
void SetNsStatus(AudioProcessing* apm, bool enable) {
RTC_DCHECK(apm);
NoiseSuppression* ns = apm->noise_suppression();
if (ns->set_level(NoiseSuppression::kHigh) != 0) {
LOG(LS_ERROR) << "Failed to set high NS level.";
return;
}
if (ns->Enable(enable) != 0) {
LOG(LS_ERROR) << "Failed to enable/disable NS: " << enable;
return;
}
LOG(LS_INFO) << "NS set to " << enable;
}
void SetTypingDetectionStatus(AudioProcessing* apm, bool enable) {
RTC_DCHECK(apm);
#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
// Typing detection takes place in TransmitMixer::PrepareDemux() and
// TransmitMixer::TypingDetection(). The typing detection algorithm takes as
// input two booleans:
// 1. A signal whether a key was pressed during the audio frame.
// 2. Whether VAD is active or not.
// TransmitMixer will not even call the detector if APM has set kVadUnknown in
// the audio frame after near end processing, so enabling/disabling VAD is
// sufficient for turning typing detection on/off.
// TODO(solenberg): Rather than relying on a side effect, consider forcing the
// feature on/off in TransmitMixer.
VoiceDetection* vd = apm->voice_detection();
if (vd->Enable(enable)) {
LOG(LS_ERROR) << "Failed to enable/disable VAD: " << enable;
return;
}
if (vd->set_likelihood(VoiceDetection::kVeryLowLikelihood)) {
LOG(LS_ERROR) << "Failed to set low VAD likelihood.";
return;
}
LOG(LS_INFO) << "VAD set to " << enable << " for typing detection.";
#endif
}
} // namespace apm_helpers
} // namespace webrtc

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2017 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.
*/
#ifndef WEBRTC_MEDIA_ENGINE_APM_HELPERS_H_
#define WEBRTC_MEDIA_ENGINE_APM_HELPERS_H_
#include "webrtc/common_types.h"
namespace webrtc {
class AudioProcessing;
class AudioDeviceModule;
namespace apm_helpers {
AgcConfig GetAgcConfig(AudioProcessing* apm);
void SetAgcConfig(AudioProcessing* apm,
const AgcConfig& config);
void SetAgcStatus(AudioProcessing* apm,
AudioDeviceModule* adm,
bool enable,
AgcModes mode);
void SetEcStatus(AudioProcessing* apm,
bool enable,
EcModes mode);
void SetEcMetricsStatus(AudioProcessing* apm, bool enable);
void SetAecmMode(AudioProcessing* apm, bool enable_cng);
void SetNsStatus(AudioProcessing* apm, bool enable);
void SetTypingDetectionStatus(AudioProcessing* apm, bool enable);
} // namespace apm_helpers
} // namespace webrtc
#endif // WEBRTC_MEDIA_ENGINE_APM_HELPERS_H_

View File

@ -0,0 +1,283 @@
/*
* Copyright (c) 2017 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/media/engine/apm_helpers.h"
#include "webrtc/media/engine/webrtcvoe.h"
#include "webrtc/modules/audio_coding/codecs/mock/mock_audio_decoder_factory.h"
#include "webrtc/modules/audio_device/include/mock_audio_device.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
#include "webrtc/voice_engine/transmit_mixer.h"
namespace webrtc {
namespace {
constexpr AgcConfig kDefaultAgcConfig = { 3, 9, true };
struct TestHelper {
TestHelper() {
// This replicates the conditions from voe_auto_test.
Config config;
config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
EXPECT_EQ(0, voe_wrapper_.base()->Init(
&mock_audio_device_,
AudioProcessing::Create(config),
MockAudioDecoderFactory::CreateEmptyFactory()));
}
AudioProcessing* apm() {
return voe_wrapper_.base()->audio_processing();
}
const AudioProcessing* apm() const {
return voe_wrapper_.base()->audio_processing();
}
test::MockAudioDeviceModule* adm() {
return &mock_audio_device_;
}
voe::TransmitMixer* transmit_mixer() {
return voe_wrapper_.base()->transmit_mixer();
}
bool GetEcMetricsStatus() const {
EchoCancellation* ec = apm()->echo_cancellation();
bool metrics_enabled = ec->are_metrics_enabled();
EXPECT_EQ(metrics_enabled, ec->is_delay_logging_enabled());
return metrics_enabled;
}
bool CanGetEcMetrics() const {
EchoCancellation* ec = apm()->echo_cancellation();
EchoCancellation::Metrics metrics;
int metrics_result = ec->GetMetrics(&metrics);
int median = 0;
int std = 0;
float fraction = 0;
int delay_metrics_result = ec->GetDelayMetrics(&median, &std, &fraction);
return metrics_result == AudioProcessing::kNoError &&
delay_metrics_result == AudioProcessing::kNoError;
}
private:
testing::NiceMock<test::MockAudioDeviceModule> mock_audio_device_;
cricket::VoEWrapper voe_wrapper_;
};
} // namespace
TEST(ApmHelpersTest, AgcConfig_DefaultConfiguration) {
TestHelper helper;
AgcConfig agc_config =
apm_helpers::GetAgcConfig(helper.apm());
EXPECT_EQ(kDefaultAgcConfig.targetLeveldBOv, agc_config.targetLeveldBOv);
EXPECT_EQ(kDefaultAgcConfig.digitalCompressionGaindB,
agc_config.digitalCompressionGaindB);
EXPECT_EQ(kDefaultAgcConfig.limiterEnable, agc_config.limiterEnable);
}
TEST(ApmHelpersTest, AgcConfig_GetAndSet) {
const AgcConfig agc_config = { 11, 17, false };
TestHelper helper;
apm_helpers::SetAgcConfig(helper.apm(), agc_config);
AgcConfig actual_config =
apm_helpers::GetAgcConfig(helper.apm());
EXPECT_EQ(agc_config.digitalCompressionGaindB,
actual_config.digitalCompressionGaindB);
EXPECT_EQ(agc_config.limiterEnable,
actual_config.limiterEnable);
EXPECT_EQ(agc_config.targetLeveldBOv,
actual_config.targetLeveldBOv);
}
TEST(ApmHelpersTest, AgcStatus_DefaultMode) {
TestHelper helper;
GainControl* gc = helper.apm()->gain_control();
#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
EXPECT_FALSE(gc->is_enabled());
EXPECT_EQ(GainControl::kFixedDigital, gc->mode());
#else
EXPECT_TRUE(gc->is_enabled());
EXPECT_EQ(GainControl::kAdaptiveAnalog, gc->mode());
#endif
}
TEST(ApmHelpersTest, AgcStatus_EnableDisable) {
TestHelper helper;
GainControl* gc = helper.apm()->gain_control();
#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
apm_helpers::SetAgcStatus(helper.apm(), helper.adm(), false,
kAgcFixedDigital);
EXPECT_FALSE(gc->is_enabled());
EXPECT_EQ(GainControl::kFixedDigital, gc->mode());
apm_helpers::SetAgcStatus(helper.apm(), helper.adm(), true,
kAgcFixedDigital);
EXPECT_TRUE(gc->is_enabled());
EXPECT_EQ(GainControl::kFixedDigital, gc->mode());
#else
EXPECT_CALL(*helper.adm(), SetAGC(false)).WillOnce(testing::Return(0));
apm_helpers::SetAgcStatus(helper.apm(), helper.adm(), false,
kAgcAdaptiveAnalog);
EXPECT_FALSE(gc->is_enabled());
EXPECT_EQ(GainControl::kAdaptiveAnalog, gc->mode());
EXPECT_CALL(*helper.adm(), SetAGC(true)).WillOnce(testing::Return(0));
apm_helpers::SetAgcStatus(helper.apm(), helper.adm(), true,
kAgcAdaptiveAnalog);
EXPECT_TRUE(gc->is_enabled());
EXPECT_EQ(GainControl::kAdaptiveAnalog, gc->mode());
#endif
}
TEST(ApmHelpersTest, EcStatus_DefaultMode) {
TestHelper helper;
EchoCancellation* ec = helper.apm()->echo_cancellation();
EchoControlMobile* ecm = helper.apm()->echo_control_mobile();
EXPECT_FALSE(ec->is_enabled());
EXPECT_FALSE(ecm->is_enabled());
}
TEST(ApmHelpersTest, EcStatus_EnableDisable) {
TestHelper helper;
EchoCancellation* ec = helper.apm()->echo_cancellation();
EchoControlMobile* ecm = helper.apm()->echo_control_mobile();
apm_helpers::SetEcStatus(helper.apm(), true, kEcAecm);
EXPECT_FALSE(ec->is_enabled());
EXPECT_TRUE(ecm->is_enabled());
apm_helpers::SetEcStatus(helper.apm(), false, kEcAecm);
EXPECT_FALSE(ec->is_enabled());
EXPECT_FALSE(ecm->is_enabled());
apm_helpers::SetEcStatus(helper.apm(), true, kEcConference);
EXPECT_TRUE(ec->is_enabled());
EXPECT_FALSE(ecm->is_enabled());
EXPECT_EQ(EchoCancellation::kHighSuppression, ec->suppression_level());
apm_helpers::SetEcStatus(helper.apm(), false, kEcConference);
EXPECT_FALSE(ec->is_enabled());
EXPECT_FALSE(ecm->is_enabled());
EXPECT_EQ(EchoCancellation::kHighSuppression, ec->suppression_level());
apm_helpers::SetEcStatus(helper.apm(), true, kEcAecm);
EXPECT_FALSE(ec->is_enabled());
EXPECT_TRUE(ecm->is_enabled());
}
TEST(ApmHelpersTest, EcMetrics_DefaultMode) {
TestHelper helper;
apm_helpers::SetEcStatus(helper.apm(), true, kEcConference);
EXPECT_TRUE(helper.GetEcMetricsStatus());
}
TEST(ApmHelpersTest, EcMetrics_CanEnableDisable) {
TestHelper helper;
apm_helpers::SetEcStatus(helper.apm(), true, kEcConference);
apm_helpers::SetEcMetricsStatus(helper.apm(), true);
EXPECT_TRUE(helper.GetEcMetricsStatus());
apm_helpers::SetEcMetricsStatus(helper.apm(), false);
EXPECT_FALSE(helper.GetEcMetricsStatus());
}
TEST(ApmHelpersTest, EcMetrics_NoStatsUnlessEcMetricsAndEcEnabled) {
TestHelper helper;
EXPECT_FALSE(helper.CanGetEcMetrics());
apm_helpers::SetEcMetricsStatus(helper.apm(), true);
EXPECT_FALSE(helper.CanGetEcMetrics());
apm_helpers::SetEcStatus(helper.apm(), true, kEcConference);
EXPECT_TRUE(helper.CanGetEcMetrics());
apm_helpers::SetEcMetricsStatus(helper.apm(), false);
EXPECT_FALSE(helper.CanGetEcMetrics());
}
TEST(ApmHelpersTest, AecmMode_DefaultMode) {
TestHelper helper;
EchoControlMobile* ecm = helper.apm()->echo_control_mobile();
EXPECT_EQ(EchoControlMobile::kSpeakerphone, ecm->routing_mode());
EXPECT_TRUE(ecm->is_comfort_noise_enabled());
}
TEST(ApmHelpersTest, AecmMode_EnableDisableCng) {
TestHelper helper;
EchoControlMobile* ecm = helper.apm()->echo_control_mobile();
apm_helpers::SetAecmMode(helper.apm(), false);
EXPECT_FALSE(ecm->is_comfort_noise_enabled());
apm_helpers::SetAecmMode(helper.apm(), true);
EXPECT_TRUE(ecm->is_comfort_noise_enabled());
}
TEST(ApmHelpersTest, NsStatus_DefaultMode) {
TestHelper helper;
NoiseSuppression* ns = helper.apm()->noise_suppression();
EXPECT_EQ(NoiseSuppression::kModerate, ns->level());
EXPECT_FALSE(ns->is_enabled());
}
TEST(ApmHelpersTest, NsStatus_EnableDisable) {
TestHelper helper;
NoiseSuppression* ns = helper.apm()->noise_suppression();
apm_helpers::SetNsStatus(helper.apm(), true);
EXPECT_EQ(NoiseSuppression::kHigh, ns->level());
EXPECT_TRUE(ns->is_enabled());
apm_helpers::SetNsStatus(helper.apm(), false);
EXPECT_EQ(NoiseSuppression::kHigh, ns->level());
EXPECT_FALSE(ns->is_enabled());
}
TEST(ApmHelpersTest, TypingDetectionStatus_DefaultMode) {
TestHelper helper;
VoiceDetection* vd = helper.apm()->voice_detection();
EXPECT_FALSE(vd->is_enabled());
}
TEST(ApmHelpersTest, TypingDetectionStatus_EnableDisable) {
TestHelper helper;
VoiceDetection* vd = helper.apm()->voice_detection();
apm_helpers::SetTypingDetectionStatus(helper.apm(), true);
EXPECT_TRUE(vd->is_enabled());
apm_helpers::SetTypingDetectionStatus(helper.apm(), false);
EXPECT_FALSE(vd->is_enabled());
}
// TODO(solenberg): Move this test to a better place - added here for the sake
// of duplicating all relevant tests from audio_processing_test.cc.
TEST(ApmHelpersTest, HighPassFilter_DefaultMode) {
TestHelper helper;
EXPECT_TRUE(helper.apm()->high_pass_filter()->is_enabled());
}
// TODO(solenberg): Move this test to a better place - added here for the sake
// of duplicating all relevant tests from audio_processing_test.cc.
TEST(ApmHelpersTest, StereoSwapping_DefaultMode) {
TestHelper helper;
EXPECT_FALSE(helper.transmit_mixer()->IsStereoChannelSwappingEnabled());
}
// TODO(solenberg): Move this test to a better place - added here for the sake
// of duplicating all relevant tests from audio_processing_test.cc.
TEST(ApmHelpersTest, StereoSwapping_EnableDisable) {
TestHelper helper;
helper.transmit_mixer()->EnableStereoChannelSwapping(true);
EXPECT_TRUE(helper.transmit_mixer()->IsStereoChannelSwappingEnabled());
helper.transmit_mixer()->EnableStereoChannelSwapping(false);
EXPECT_FALSE(helper.transmit_mixer()->IsStereoChannelSwappingEnabled());
}
} // namespace webrtc

View File

@ -27,6 +27,12 @@
#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
namespace webrtc {
namespace voe {
class TransmitMixer;
} // namespace voe
} // namespace webrtc
namespace cricket {
static const int kOpusBandwidthNb = 4000;
@ -53,8 +59,7 @@ static const int kOpusBandwidthFb = 20000;
#define WEBRTC_FUNC(method, args) int method args override
class FakeWebRtcVoiceEngine
: public webrtc::VoEAudioProcessing,
public webrtc::VoEBase, public webrtc::VoECodec,
: public webrtc::VoEBase, public webrtc::VoECodec,
public webrtc::VoEHardware,
public webrtc::VoEVolumeControl {
public:
@ -64,15 +69,14 @@ class FakeWebRtcVoiceEngine
bool neteq_fast_accelerate = false;
};
explicit FakeWebRtcVoiceEngine(webrtc::AudioProcessing* apm) : apm_(apm) {
memset(&agc_config_, 0, sizeof(agc_config_));
explicit FakeWebRtcVoiceEngine(webrtc::AudioProcessing* apm,
webrtc::voe::TransmitMixer* transmit_mixer)
: apm_(apm), transmit_mixer_(transmit_mixer) {
}
~FakeWebRtcVoiceEngine() override {
RTC_CHECK(channels_.empty());
}
bool ec_metrics_enabled() const { return ec_metrics_enabled_; }
bool IsInited() const { return inited_; }
int GetLastChannel() const { return last_channel_; }
int GetNumChannels() const { return static_cast<int>(channels_.size()); }
@ -104,6 +108,9 @@ class FakeWebRtcVoiceEngine
webrtc::AudioDeviceModule* audio_device_module() override {
return nullptr;
}
webrtc::voe::TransmitMixer* transmit_mixer() override {
return transmit_mixer_;
}
WEBRTC_FUNC(CreateChannel, ()) {
return CreateChannel(webrtc::VoEBase::ChannelConfig());
}
@ -233,98 +240,6 @@ class FakeWebRtcVoiceEngine
WEBRTC_STUB(SetOutputVolumePan, (int channel, float left, float right));
WEBRTC_STUB(GetOutputVolumePan, (int channel, float& left, float& right));
// webrtc::VoEAudioProcessing
WEBRTC_FUNC(SetNsStatus, (bool enable, webrtc::NsModes mode)) {
ns_enabled_ = enable;
ns_mode_ = mode;
return 0;
}
WEBRTC_FUNC(GetNsStatus, (bool& enabled, webrtc::NsModes& mode)) {
enabled = ns_enabled_;
mode = ns_mode_;
return 0;
}
WEBRTC_FUNC(SetAgcStatus, (bool enable, webrtc::AgcModes mode)) {
agc_enabled_ = enable;
agc_mode_ = mode;
return 0;
}
WEBRTC_FUNC(GetAgcStatus, (bool& enabled, webrtc::AgcModes& mode)) {
enabled = agc_enabled_;
mode = agc_mode_;
return 0;
}
WEBRTC_FUNC(SetAgcConfig, (webrtc::AgcConfig config)) {
agc_config_ = config;
return 0;
}
WEBRTC_FUNC(GetAgcConfig, (webrtc::AgcConfig& config)) {
config = agc_config_;
return 0;
}
WEBRTC_FUNC(SetEcStatus, (bool enable, webrtc::EcModes mode)) {
ec_enabled_ = enable;
ec_mode_ = mode;
return 0;
}
WEBRTC_FUNC(GetEcStatus, (bool& enabled, webrtc::EcModes& mode)) {
enabled = ec_enabled_;
mode = ec_mode_;
return 0;
}
WEBRTC_STUB(EnableDriftCompensation, (bool enable))
WEBRTC_BOOL_STUB(DriftCompensationEnabled, ())
WEBRTC_VOID_STUB(SetDelayOffsetMs, (int offset))
WEBRTC_STUB(DelayOffsetMs, ());
WEBRTC_FUNC(SetAecmMode, (webrtc::AecmModes mode, bool enableCNG)) {
aecm_mode_ = mode;
cng_enabled_ = enableCNG;
return 0;
}
WEBRTC_FUNC(GetAecmMode, (webrtc::AecmModes& mode, bool& enabledCNG)) {
mode = aecm_mode_;
enabledCNG = cng_enabled_;
return 0;
}
WEBRTC_STUB(VoiceActivityIndicator, (int channel));
WEBRTC_FUNC(SetEcMetricsStatus, (bool enable)) {
ec_metrics_enabled_ = enable;
return 0;
}
WEBRTC_STUB(GetEcMetricsStatus, (bool& enabled));
WEBRTC_STUB(GetEchoMetrics, (int& ERL, int& ERLE, int& RERL, int& A_NLP));
WEBRTC_STUB(GetEcDelayMetrics, (int& delay_median, int& delay_std,
float& fraction_poor_delays));
WEBRTC_STUB(StartDebugRecording, (const char* fileNameUTF8));
WEBRTC_STUB(StartDebugRecording, (FILE* handle));
WEBRTC_STUB(StopDebugRecording, ());
WEBRTC_FUNC(SetTypingDetectionStatus, (bool enable)) {
typing_detection_enabled_ = enable;
return 0;
}
WEBRTC_FUNC(GetTypingDetectionStatus, (bool& enabled)) {
enabled = typing_detection_enabled_;
return 0;
}
WEBRTC_STUB(TimeSinceLastTyping, (int& seconds));
WEBRTC_STUB(SetTypingDetectionParameters, (int timeWindow,
int costPerTyping,
int reportingThreshold,
int penaltyDecay,
int typeEventDelay));
int EnableHighPassFilter(bool enable) override {
highpass_filter_enabled_ = enable;
return 0;
}
bool IsHighPassFilterEnabled() override {
return highpass_filter_enabled_;
}
bool IsStereoChannelSwappingEnabled() override {
return stereo_swapping_enabled_;
}
void EnableStereoChannelSwapping(bool enable) override {
stereo_swapping_enabled_ = enable;
}
size_t GetNetEqCapacity() const {
auto ch = channels_.find(last_channel_);
RTC_DCHECK(ch != channels_.end());
@ -341,20 +256,8 @@ class FakeWebRtcVoiceEngine
int last_channel_ = -1;
std::map<int, Channel*> channels_;
bool fail_create_channel_ = false;
bool ec_enabled_ = false;
bool ec_metrics_enabled_ = false;
bool cng_enabled_ = false;
bool ns_enabled_ = false;
bool agc_enabled_ = false;
bool highpass_filter_enabled_ = false;
bool stereo_swapping_enabled_ = false;
bool typing_detection_enabled_ = false;
webrtc::EcModes ec_mode_ = webrtc::kEcDefault;
webrtc::AecmModes aecm_mode_ = webrtc::kAecmSpeakerphone;
webrtc::NsModes ns_mode_ = webrtc::kNsDefault;
webrtc::AgcModes agc_mode_ = webrtc::kAgcDefault;
webrtc::AgcConfig agc_config_;
webrtc::AudioProcessing* apm_ = nullptr;
webrtc::voe::TransmitMixer* transmit_mixer_ = nullptr;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(FakeWebRtcVoiceEngine);
};

View File

@ -17,7 +17,6 @@
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_device/include/audio_device.h"
#include "webrtc/voice_engine/include/voe_audio_processing.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_codec.h"
#include "webrtc/voice_engine/include/voe_errors.h"
@ -78,17 +77,15 @@ class scoped_voe_ptr {
class VoEWrapper {
public:
VoEWrapper()
: engine_(webrtc::VoiceEngine::Create()), processing_(engine_),
: engine_(webrtc::VoiceEngine::Create()),
base_(engine_), codec_(engine_), hw_(engine_),
volume_(engine_) {
}
VoEWrapper(webrtc::VoEAudioProcessing* processing,
webrtc::VoEBase* base,
VoEWrapper(webrtc::VoEBase* base,
webrtc::VoECodec* codec,
webrtc::VoEHardware* hw,
webrtc::VoEVolumeControl* volume)
: engine_(NULL),
processing_(processing),
base_(base),
codec_(codec),
hw_(hw),
@ -96,7 +93,6 @@ class VoEWrapper {
}
~VoEWrapper() {}
webrtc::VoiceEngine* engine() const { return engine_.get(); }
webrtc::VoEAudioProcessing* processing() const { return processing_.get(); }
webrtc::VoEBase* base() const { return base_.get(); }
webrtc::VoECodec* codec() const { return codec_.get(); }
webrtc::VoEHardware* hw() const { return hw_.get(); }
@ -105,7 +101,6 @@ class VoEWrapper {
private:
scoped_voe_engine engine_;
scoped_voe_ptr<webrtc::VoEAudioProcessing> processing_;
scoped_voe_ptr<webrtc::VoEBase> base_;
scoped_voe_ptr<webrtc::VoECodec> codec_;
scoped_voe_ptr<webrtc::VoEHardware> hw_;

View File

@ -32,6 +32,7 @@
#include "webrtc/media/base/audiosource.h"
#include "webrtc/media/base/mediaconstants.h"
#include "webrtc/media/base/streamparams.h"
#include "webrtc/media/engine/apm_helpers.h"
#include "webrtc/media/engine/payload_type_mapper.h"
#include "webrtc/media/engine/webrtcmediaengine.h"
#include "webrtc/media/engine/webrtcvoe.h"
@ -40,6 +41,7 @@
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/system_wrappers/include/field_trial.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/voice_engine/transmit_mixer.h"
namespace cricket {
namespace {
@ -559,7 +561,7 @@ rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps,
return rtc::Optional<int>(codec_rate);
}
} // namespace {
} // namespace
bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in,
webrtc::CodecInst* out) {
@ -620,10 +622,12 @@ WebRtcVoiceEngine::WebRtcVoiceEngine(
apm_ = voe_wrapper_->base()->audio_processing();
RTC_DCHECK(apm_);
transmit_mixer_ = voe_wrapper_->base()->transmit_mixer();
RTC_DCHECK(transmit_mixer_);
// Save the default AGC configuration settings. This must happen before
// calling ApplyOptions or the default will be overwritten.
int error = voe_wrapper_->processing()->GetAgcConfig(default_agc_config_);
RTC_DCHECK_EQ(0, error);
default_agc_config_ = webrtc::apm_helpers::GetAgcConfig(apm_);
// Set default engine options.
{
@ -680,9 +684,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
// kEcConference is AEC with high suppression.
webrtc::EcModes ec_mode = webrtc::kEcConference;
webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone;
webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
webrtc::NsModes ns_mode = webrtc::kNsHighSuppression;
if (options.aecm_generate_comfort_noise) {
LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
<< *options.aecm_generate_comfort_noise
@ -729,8 +731,6 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
options.intelligibility_enhancer = rtc::Optional<bool>(false);
#endif
webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
if (options.echo_cancellation) {
// Check if platform supports built-in EC. Currently only supported on
// Android and in combination with Java based audio layer.
@ -751,26 +751,14 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
LOG(LS_INFO) << "Disabling EC since built-in EC will be used instead";
}
}
if (voep->SetEcStatus(*options.echo_cancellation, ec_mode) == -1) {
LOG_RTCERR2(SetEcStatus, *options.echo_cancellation, ec_mode);
return false;
} else {
LOG(LS_INFO) << "Echo control set to " << *options.echo_cancellation
<< " with mode " << ec_mode;
}
webrtc::apm_helpers::SetEcStatus(
apm(), *options.echo_cancellation, ec_mode);
#if !defined(ANDROID)
// TODO(ajm): Remove the error return on Android from webrtc.
if (voep->SetEcMetricsStatus(*options.echo_cancellation) == -1) {
LOG_RTCERR1(SetEcMetricsStatus, *options.echo_cancellation);
return false;
}
webrtc::apm_helpers::SetEcMetricsStatus(apm(), *options.echo_cancellation);
#endif
if (ec_mode == webrtc::kEcAecm) {
bool cn = options.aecm_generate_comfort_noise.value_or(false);
if (voep->SetAecmMode(aecm_mode, cn) != 0) {
LOG_RTCERR2(SetAecmMode, aecm_mode, cn);
return false;
}
webrtc::apm_helpers::SetAecmMode(apm(), cn);
}
}
@ -785,17 +773,12 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
LOG(LS_INFO) << "Disabling AGC since built-in AGC will be used instead";
}
}
if (voep->SetAgcStatus(*options.auto_gain_control, agc_mode) == -1) {
LOG_RTCERR2(SetAgcStatus, *options.auto_gain_control, agc_mode);
return false;
} else {
LOG(LS_INFO) << "Auto gain set to " << *options.auto_gain_control
<< " with mode " << agc_mode;
}
webrtc::apm_helpers::SetAgcStatus(
apm(), adm(), *options.auto_gain_control, agc_mode);
}
if (options.tx_agc_target_dbov || options.tx_agc_digital_compression_gain ||
options.tx_agc_limiter) {
options.tx_agc_limiter || options.adjust_agc_delta) {
// Override default_agc_config_. Generally, an unset option means "leave
// the VoE bits alone" in this function, so we want whatever is set to be
// stored as the new "default". If we didn't, then setting e.g.
@ -811,13 +794,15 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
default_agc_config_.digitalCompressionGaindB);
default_agc_config_.limiterEnable =
options.tx_agc_limiter.value_or(default_agc_config_.limiterEnable);
if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) {
LOG_RTCERR3(SetAgcConfig,
default_agc_config_.targetLeveldBOv,
default_agc_config_.digitalCompressionGaindB,
default_agc_config_.limiterEnable);
return false;
webrtc::AgcConfig config = default_agc_config_;
if (options.adjust_agc_delta) {
config.targetLeveldBOv -= *options.adjust_agc_delta;
LOG(LS_INFO) << "Adjusting AGC level from default -"
<< default_agc_config_.targetLeveldBOv << "dB to -"
<< config.targetLeveldBOv << "dB";
}
webrtc::apm_helpers::SetAgcConfig(apm_, config);
}
if (options.intelligibility_enhancer) {
@ -840,22 +825,12 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
LOG(LS_INFO) << "Disabling NS since built-in NS will be used instead";
}
}
if (voep->SetNsStatus(*options.noise_suppression, ns_mode) == -1) {
LOG_RTCERR2(SetNsStatus, *options.noise_suppression, ns_mode);
return false;
} else {
LOG(LS_INFO) << "Noise suppression set to " << *options.noise_suppression
<< " with mode " << ns_mode;
}
webrtc::apm_helpers::SetNsStatus(apm(), *options.noise_suppression);
}
if (options.stereo_swapping) {
LOG(LS_INFO) << "Stereo swapping enabled? " << *options.stereo_swapping;
voep->EnableStereoChannelSwapping(*options.stereo_swapping);
if (voep->IsStereoChannelSwappingEnabled() != *options.stereo_swapping) {
LOG_RTCERR1(EnableStereoChannelSwapping, *options.stereo_swapping);
return false;
}
transmit_mixer()->EnableStereoChannelSwapping(*options.stereo_swapping);
}
if (options.audio_jitter_buffer_max_packets) {
@ -874,17 +849,8 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
if (options.typing_detection) {
LOG(LS_INFO) << "Typing detection is enabled? "
<< *options.typing_detection;
if (voep->SetTypingDetectionStatus(*options.typing_detection) == -1) {
// In case of error, log the info and continue
LOG_RTCERR1(SetTypingDetectionStatus, *options.typing_detection);
}
}
if (options.adjust_agc_delta) {
LOG(LS_INFO) << "Adjust agc delta is " << *options.adjust_agc_delta;
if (!AdjustAgcLevel(*options.adjust_agc_delta)) {
return false;
}
webrtc::apm_helpers::SetTypingDetectionStatus(
apm(), *options.typing_detection);
}
webrtc::Config config;
@ -1067,25 +1033,6 @@ void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel* channel) {
channels_.erase(it);
}
// Adjusts the default AGC target level by the specified delta.
// NB: If we start messing with other config fields, we'll want
// to save the current webrtc::AgcConfig as well.
bool WebRtcVoiceEngine::AdjustAgcLevel(int delta) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
webrtc::AgcConfig config = default_agc_config_;
config.targetLeveldBOv -= delta;
LOG(LS_INFO) << "Adjusting AGC level from default -"
<< default_agc_config_.targetLeveldBOv << "dB to -"
<< config.targetLeveldBOv << "dB";
if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) {
LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv);
return false;
}
return true;
}
bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file,
int64_t max_size_bytes) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
@ -1148,6 +1095,12 @@ webrtc::AudioProcessing* WebRtcVoiceEngine::apm() {
return apm_;
}
webrtc::voe::TransmitMixer* WebRtcVoiceEngine::transmit_mixer() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RTC_DCHECK(transmit_mixer_);
return transmit_mixer_;
}
AudioCodecs WebRtcVoiceEngine::CollectRecvCodecs() const {
PayloadTypeMapper mapper;
AudioCodecs out;
@ -1884,7 +1837,7 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
it.second->RecreateAudioSendStream(audio_network_adatptor_config);
}
LOG(LS_INFO) << "Set voice channel options. Current options: "
LOG(LS_INFO) << "Set voice channel options. Current options: "
<< options_.ToString();
return true;
}

View File

@ -30,6 +30,12 @@
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/pc/channel.h"
namespace webrtc {
namespace voe {
class TransmitMixer;
} // namespace voe
} // namespace webrtc
namespace cricket {
class AudioDeviceModule;
@ -75,10 +81,6 @@ class WebRtcVoiceEngine final : public webrtc::TraceCallback {
void RegisterChannel(WebRtcVoiceMediaChannel* channel);
void UnregisterChannel(WebRtcVoiceMediaChannel* channel);
// Called by WebRtcVoiceMediaChannel to set a gain offset from
// the default AGC target level.
bool AdjustAgcLevel(int delta);
VoEWrapper* voe() { return voe_wrapper_.get(); }
int GetLastEngineError();
@ -109,6 +111,7 @@ class WebRtcVoiceEngine final : public webrtc::TraceCallback {
int CreateVoEChannel();
webrtc::AudioDeviceModule* adm();
webrtc::AudioProcessing* apm();
webrtc::voe::TransmitMixer* transmit_mixer();
AudioCodecs CollectRecvCodecs() const;
@ -120,6 +123,8 @@ class WebRtcVoiceEngine final : public webrtc::TraceCallback {
rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory_;
// Reference to the APM, owned by VoE.
webrtc::AudioProcessing* apm_ = nullptr;
// Reference to the TransmitMixer, owned by VoE.
webrtc::voe::TransmitMixer* transmit_mixer_ = nullptr;
// The primary instance of WebRtc VoiceEngine.
std::unique_ptr<VoEWrapper> voe_wrapper_;
rtc::scoped_refptr<webrtc::AudioState> audio_state_;

View File

@ -13,7 +13,6 @@
#include "webrtc/api/audio_codecs/builtin_audio_decoder_factory.h"
#include "webrtc/base/arraysize.h"
#include "webrtc/base/byteorder.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/safe_conversions.h"
#include "webrtc/call/call.h"
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
@ -29,6 +28,8 @@
#include "webrtc/modules/audio_processing/include/mock_audio_processing.h"
#include "webrtc/pc/channel.h"
#include "webrtc/test/field_trial.h"
#include "webrtc/test/gtest.h"
#include "webrtc/voice_engine/transmit_mixer.h"
using testing::Return;
using testing::StrictMock;
@ -58,14 +59,20 @@ constexpr int kRtpHistoryMs = 5000;
class FakeVoEWrapper : public cricket::VoEWrapper {
public:
explicit FakeVoEWrapper(cricket::FakeWebRtcVoiceEngine* engine)
: cricket::VoEWrapper(engine, // processing
engine, // base
: cricket::VoEWrapper(engine, // base
engine, // codec
engine, // hw
engine) { // volume
}
};
class MockTransmitMixer : public webrtc::voe::TransmitMixer {
public:
MockTransmitMixer() = default;
virtual ~MockTransmitMixer() = default;
MOCK_METHOD1(EnableStereoChannelSwapping, void(bool enable));
};
} // namespace
// Tests that our stub library "works".
@ -76,11 +83,14 @@ TEST(WebRtcVoiceEngineTestStubLibrary, StartupShutdown) {
EXPECT_CALL(adm, BuiltInAECIsAvailable()).WillOnce(Return(false));
EXPECT_CALL(adm, BuiltInAGCIsAvailable()).WillOnce(Return(false));
EXPECT_CALL(adm, BuiltInNSIsAvailable()).WillOnce(Return(false));
EXPECT_CALL(adm, SetAGC(true)).WillOnce(Return(0));
StrictMock<webrtc::test::MockAudioProcessing> apm;
EXPECT_CALL(apm, ApplyConfig(testing::_));
EXPECT_CALL(apm, SetExtraOptions(testing::_));
EXPECT_CALL(apm, Initialize()).WillOnce(Return(0));
cricket::FakeWebRtcVoiceEngine voe(&apm);
StrictMock<MockTransmitMixer> transmit_mixer;
EXPECT_CALL(transmit_mixer, EnableStereoChannelSwapping(false));
cricket::FakeWebRtcVoiceEngine voe(&apm, &transmit_mixer);
EXPECT_FALSE(voe.IsInited());
{
cricket::WebRtcVoiceEngine engine(
@ -105,16 +115,35 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
WebRtcVoiceEngineTestFake() : WebRtcVoiceEngineTestFake("") {}
explicit WebRtcVoiceEngineTestFake(const char* field_trials)
: call_(webrtc::Call::Config(&event_log_)), voe_(&apm_),
: apm_gc_(*apm_.gain_control()), apm_ec_(*apm_.echo_cancellation()),
apm_ns_(*apm_.noise_suppression()), apm_vd_(*apm_.voice_detection()),
call_(webrtc::Call::Config(&event_log_)), voe_(&apm_, &transmit_mixer_),
override_field_trials_(field_trials) {
// AudioDeviceModule.
EXPECT_CALL(adm_, AddRef()).WillOnce(Return(0));
EXPECT_CALL(adm_, Release()).WillOnce(Return(0));
EXPECT_CALL(adm_, BuiltInAECIsAvailable()).WillOnce(Return(false));
EXPECT_CALL(adm_, BuiltInAGCIsAvailable()).WillOnce(Return(false));
EXPECT_CALL(adm_, BuiltInNSIsAvailable()).WillOnce(Return(false));
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
// AudioProcessing.
EXPECT_CALL(apm_, ApplyConfig(testing::_));
EXPECT_CALL(apm_, SetExtraOptions(testing::_));
EXPECT_CALL(apm_, Initialize()).WillOnce(Return(0));
// Default Options.
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_vd_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(transmit_mixer_, EnableStereoChannelSwapping(false));
// Init does not overwrite default AGC config.
EXPECT_CALL(apm_gc_, target_level_dbfs()).WillOnce(Return(1));
EXPECT_CALL(apm_gc_, compression_gain_db()).WillRepeatedly(Return(5));
EXPECT_CALL(apm_gc_, is_limiter_enabled()).WillRepeatedly(Return(true));
EXPECT_CALL(apm_gc_, set_target_level_dbfs(1)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, set_compression_gain_db(5)).WillRepeatedly(Return(0));
EXPECT_CALL(apm_gc_, enable_limiter(true)).WillRepeatedly(Return(0));
// TODO(kwiberg): We should use a mock AudioDecoderFactory, but a bunch of
// the tests here probe the specific set of codecs provided by the builtin
// factory. Those tests should probably be moved elsewhere.
@ -123,6 +152,8 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
new FakeVoEWrapper(&voe_)));
send_parameters_.codecs.push_back(kPcmuCodec);
recv_parameters_.codecs.push_back(kPcmuCodec);
// Default Options.
EXPECT_TRUE(IsHighPassFilterEnabled());
}
bool SetupChannel() {
@ -607,6 +638,11 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
protected:
StrictMock<webrtc::test::MockAudioDeviceModule> adm_;
StrictMock<webrtc::test::MockAudioProcessing> apm_;
webrtc::test::MockGainControl& apm_gc_;
webrtc::test::MockEchoCancellation& apm_ec_;
webrtc::test::MockNoiseSuppression& apm_ns_;
webrtc::test::MockVoiceDetection& apm_vd_;
StrictMock<MockTransmitMixer> transmit_mixer_;
webrtc::RtcEventLogNullImpl event_log_;
cricket::FakeCall call_;
cricket::FakeWebRtcVoiceEngine voe_;
@ -2450,46 +2486,37 @@ TEST_F(WebRtcVoiceEngineTestFake, PlayoutWithMultipleStreams) {
// and start sending on it.
TEST_F(WebRtcVoiceEngineTestFake, CodianSend) {
EXPECT_TRUE(SetupSendStream());
cricket::AudioOptions options_adjust_agc;
options_adjust_agc.adjust_agc_delta = rtc::Optional<int>(-10);
webrtc::AgcConfig agc_config;
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
EXPECT_EQ(0, agc_config.targetLeveldBOv);
send_parameters_.options = options_adjust_agc;
send_parameters_.options.adjust_agc_delta = rtc::Optional<int>(-10);
EXPECT_CALL(apm_gc_,
set_target_level_dbfs(11)).Times(2).WillRepeatedly(Return(0));
SetSendParameters(send_parameters_);
SetSend(true);
EXPECT_TRUE(GetSendStream(kSsrc1).IsSending());
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
EXPECT_EQ(agc_config.targetLeveldBOv, 10); // level was attenuated
SetSend(false);
EXPECT_FALSE(GetSendStream(kSsrc1).IsSending());
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
}
TEST_F(WebRtcVoiceEngineTestFake, TxAgcConfigViaOptions) {
EXPECT_TRUE(SetupSendStream());
EXPECT_CALL(adm_,
BuiltInAGCIsAvailable()).Times(2).WillRepeatedly(Return(false));
webrtc::AgcConfig agc_config;
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
EXPECT_EQ(0, agc_config.targetLeveldBOv);
EXPECT_CALL(adm_, SetAGC(true)).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).Times(2).WillOnce(Return(0));
send_parameters_.options.tx_agc_target_dbov = rtc::Optional<uint16_t>(3);
send_parameters_.options.tx_agc_digital_compression_gain =
rtc::Optional<uint16_t>(9);
send_parameters_.options.tx_agc_limiter = rtc::Optional<bool>(true);
send_parameters_.options.auto_gain_control = rtc::Optional<bool>(true);
EXPECT_CALL(apm_gc_, set_target_level_dbfs(3)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, set_compression_gain_db(9)).WillRepeatedly(Return(0));
EXPECT_CALL(apm_gc_, enable_limiter(true)).WillRepeatedly(Return(0));
SetSendParameters(send_parameters_);
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
EXPECT_EQ(3, agc_config.targetLeveldBOv);
EXPECT_EQ(9, agc_config.digitalCompressionGaindB);
EXPECT_TRUE(agc_config.limiterEnable);
// Check interaction with adjust_agc_delta. Both should be respected, for
// backwards compatibility.
send_parameters_.options.adjust_agc_delta = rtc::Optional<int>(-10);
EXPECT_CALL(apm_gc_, set_target_level_dbfs(13)).WillOnce(Return(0));
SetSendParameters(send_parameters_);
EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
EXPECT_EQ(13, agc_config.targetLeveldBOv);
}
TEST_F(WebRtcVoiceEngineTestFake, SampleRatesViaOptions) {
@ -2957,202 +2984,102 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
BuiltInAGCIsAvailable()).Times(4).WillRepeatedly(Return(false));
EXPECT_CALL(adm_,
BuiltInNSIsAvailable()).Times(2).WillRepeatedly(Return(false));
bool ec_enabled;
webrtc::EcModes ec_mode;
webrtc::AecmModes aecm_mode;
bool cng_enabled;
bool agc_enabled;
webrtc::AgcModes agc_mode;
webrtc::AgcConfig agc_config;
bool ns_enabled;
webrtc::NsModes ns_mode;
bool stereo_swapping_enabled;
bool typing_detection_enabled;
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAecmMode(aecm_mode, cng_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetAgcConfig(agc_config);
voe_.GetNsStatus(ns_enabled, ns_mode);
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_FALSE(cng_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
EXPECT_TRUE(ns_enabled);
EXPECT_TRUE(IsHighPassFilterEnabled());
EXPECT_FALSE(stereo_swapping_enabled);
EXPECT_TRUE(typing_detection_enabled);
EXPECT_EQ(ec_mode, webrtc::kEcConference);
EXPECT_EQ(ns_mode, webrtc::kNsHighSuppression);
EXPECT_EQ(50, voe_.GetNetEqCapacity());
EXPECT_FALSE(voe_.GetNetEqFastAccelerate());
// Nothing set in AudioOptions, so everything should be as default.
send_parameters_.options = cricket::AudioOptions();
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAecmMode(aecm_mode, cng_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetAgcConfig(agc_config);
voe_.GetNsStatus(ns_enabled, ns_mode);
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_FALSE(cng_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
EXPECT_TRUE(ns_enabled);
EXPECT_TRUE(IsHighPassFilterEnabled());
EXPECT_FALSE(stereo_swapping_enabled);
EXPECT_TRUE(typing_detection_enabled);
EXPECT_EQ(ec_mode, webrtc::kEcConference);
EXPECT_EQ(ns_mode, webrtc::kNsHighSuppression);
EXPECT_EQ(50, voe_.GetNetEqCapacity());
EXPECT_FALSE(voe_.GetNetEqFastAccelerate());
// Turn echo cancellation off
EXPECT_CALL(apm_ec_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(false)).WillOnce(Return(0));
send_parameters_.options.echo_cancellation = rtc::Optional<bool>(false);
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
EXPECT_FALSE(ec_enabled);
// Turn echo cancellation back on, with settings, and make sure
// nothing else changed.
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
send_parameters_.options.echo_cancellation = rtc::Optional<bool>(true);
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAecmMode(aecm_mode, cng_enabled);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetAgcConfig(agc_config);
voe_.GetNsStatus(ns_enabled, ns_mode);
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_TRUE(agc_enabled);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
EXPECT_TRUE(ns_enabled);
EXPECT_TRUE(IsHighPassFilterEnabled());
EXPECT_FALSE(stereo_swapping_enabled);
EXPECT_TRUE(typing_detection_enabled);
EXPECT_EQ(ec_mode, webrtc::kEcConference);
EXPECT_EQ(ns_mode, webrtc::kNsHighSuppression);
// Turn on delay agnostic aec and make sure nothing change w.r.t. echo
// control.
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
send_parameters_.options.delay_agnostic_aec = rtc::Optional<bool>(true);
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAecmMode(aecm_mode, cng_enabled);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_EQ(ec_mode, webrtc::kEcConference);
// Turn off echo cancellation and delay agnostic aec.
EXPECT_CALL(apm_ec_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(false)).WillOnce(Return(0));
send_parameters_.options.delay_agnostic_aec = rtc::Optional<bool>(false);
send_parameters_.options.extended_filter_aec = rtc::Optional<bool>(false);
send_parameters_.options.echo_cancellation = rtc::Optional<bool>(false);
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
EXPECT_FALSE(ec_enabled);
// Turning delay agnostic aec back on should also turn on echo cancellation.
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
send_parameters_.options.delay_agnostic_aec = rtc::Optional<bool>(true);
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(voe_.ec_metrics_enabled());
EXPECT_EQ(ec_mode, webrtc::kEcConference);
// Turn off AGC
EXPECT_CALL(adm_, SetAGC(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(false)).WillOnce(Return(0));
send_parameters_.options.auto_gain_control = rtc::Optional<bool>(false);
SetSendParameters(send_parameters_);
voe_.GetAgcStatus(agc_enabled, agc_mode);
EXPECT_FALSE(agc_enabled);
// Turn AGC back on
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
send_parameters_.options.auto_gain_control = rtc::Optional<bool>(true);
send_parameters_.options.adjust_agc_delta = rtc::Optional<int>();
SetSendParameters(send_parameters_);
voe_.GetAgcStatus(agc_enabled, agc_mode);
EXPECT_TRUE(agc_enabled);
voe_.GetAgcConfig(agc_config);
EXPECT_EQ(0, agc_config.targetLeveldBOv);
// Turn off other options (and stereo swapping on).
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_vd_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(transmit_mixer_, EnableStereoChannelSwapping(true));
send_parameters_.options.noise_suppression = rtc::Optional<bool>(false);
send_parameters_.options.highpass_filter = rtc::Optional<bool>(false);
send_parameters_.options.typing_detection = rtc::Optional<bool>(false);
send_parameters_.options.stereo_swapping = rtc::Optional<bool>(true);
SetSendParameters(send_parameters_);
voe_.GetNsStatus(ns_enabled, ns_mode);
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_FALSE(ns_enabled);
EXPECT_FALSE(IsHighPassFilterEnabled());
EXPECT_FALSE(typing_detection_enabled);
EXPECT_TRUE(stereo_swapping_enabled);
// Set options again to ensure it has no impact.
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_vd_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(transmit_mixer_, EnableStereoChannelSwapping(true));
SetSendParameters(send_parameters_);
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
EXPECT_TRUE(ec_enabled);
EXPECT_EQ(webrtc::kEcConference, ec_mode);
EXPECT_FALSE(ns_enabled);
EXPECT_EQ(webrtc::kNsHighSuppression, ns_mode);
}
TEST_F(WebRtcVoiceEngineTestFake, DefaultOptions) {
EXPECT_TRUE(SetupSendStream());
bool ec_enabled;
webrtc::EcModes ec_mode;
bool agc_enabled;
webrtc::AgcModes agc_mode;
bool ns_enabled;
webrtc::NsModes ns_mode;
bool stereo_swapping_enabled;
bool typing_detection_enabled;
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled();
voe_.GetTypingDetectionStatus(typing_detection_enabled);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_TRUE(ns_enabled);
EXPECT_TRUE(IsHighPassFilterEnabled());
EXPECT_TRUE(typing_detection_enabled);
EXPECT_FALSE(stereo_swapping_enabled);
}
TEST_F(WebRtcVoiceEngineTestFake, InitDoesNotOverwriteDefaultAgcConfig) {
webrtc::AgcConfig set_config = {0};
set_config.targetLeveldBOv = 3;
set_config.digitalCompressionGaindB = 9;
set_config.limiterEnable = true;
EXPECT_EQ(0, voe_.SetAgcConfig(set_config));
webrtc::AgcConfig config = {0};
EXPECT_EQ(0, voe_.GetAgcConfig(config));
EXPECT_EQ(set_config.targetLeveldBOv, config.targetLeveldBOv);
EXPECT_EQ(set_config.digitalCompressionGaindB,
config.digitalCompressionGaindB);
EXPECT_EQ(set_config.limiterEnable, config.limiterEnable);
}
TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
EXPECT_TRUE(SetupSendStream());
EXPECT_CALL(adm_,
BuiltInAECIsAvailable()).Times(9).WillRepeatedly(Return(false));
BuiltInAECIsAvailable()).Times(8).WillRepeatedly(Return(false));
EXPECT_CALL(adm_,
BuiltInAGCIsAvailable()).Times(9).WillRepeatedly(Return(false));
BuiltInAGCIsAvailable()).Times(8).WillRepeatedly(Return(false));
EXPECT_CALL(adm_,
BuiltInNSIsAvailable()).Times(9).WillRepeatedly(Return(false));
BuiltInNSIsAvailable()).Times(8).WillRepeatedly(Return(false));
EXPECT_CALL(adm_,
RecordingIsInitialized()).Times(2).WillRepeatedly(Return(false));
EXPECT_CALL(adm_, Recording()).Times(2).WillRepeatedly(Return(false));
@ -3180,6 +3107,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
parameters_options_all.options.echo_cancellation = rtc::Optional<bool>(true);
parameters_options_all.options.auto_gain_control = rtc::Optional<bool>(true);
parameters_options_all.options.noise_suppression = rtc::Optional<bool>(true);
EXPECT_CALL(adm_, SetAGC(true)).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(apm_ns_, Enable(true)).Times(2).WillRepeatedly(Return(0));
EXPECT_TRUE(channel1->SetSendParameters(parameters_options_all));
EXPECT_EQ(parameters_options_all.options, channel1->options());
EXPECT_TRUE(channel2->SetSendParameters(parameters_options_all));
@ -3189,6 +3121,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
cricket::AudioSendParameters parameters_options_no_ns = send_parameters_;
parameters_options_no_ns.options.noise_suppression =
rtc::Optional<bool>(false);
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(false)).WillOnce(Return(0));
EXPECT_TRUE(channel1->SetSendParameters(parameters_options_no_ns));
cricket::AudioOptions expected_options = parameters_options_all.options;
expected_options.echo_cancellation = rtc::Optional<bool>(true);
@ -3200,64 +3137,55 @@ TEST_F(WebRtcVoiceEngineTestFake, SetOptionOverridesViaChannels) {
cricket::AudioSendParameters parameters_options_no_agc = send_parameters_;
parameters_options_no_agc.options.auto_gain_control =
rtc::Optional<bool>(false);
EXPECT_CALL(adm_, SetAGC(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(true)).WillOnce(Return(0));
EXPECT_TRUE(channel2->SetSendParameters(parameters_options_no_agc));
expected_options.echo_cancellation = rtc::Optional<bool>(true);
expected_options.auto_gain_control = rtc::Optional<bool>(false);
expected_options.noise_suppression = rtc::Optional<bool>(true);
EXPECT_EQ(expected_options, channel2->options());
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(true)).WillOnce(Return(0));
EXPECT_TRUE(channel_->SetSendParameters(parameters_options_all));
bool ec_enabled;
webrtc::EcModes ec_mode;
bool agc_enabled;
webrtc::AgcModes agc_mode;
bool ns_enabled;
webrtc::NsModes ns_mode;
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_TRUE(ns_enabled);
EXPECT_CALL(adm_, SetAGC(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(false)).WillOnce(Return(0));
channel1->SetSend(true);
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
EXPECT_TRUE(ec_enabled);
EXPECT_TRUE(agc_enabled);
EXPECT_FALSE(ns_enabled);
EXPECT_CALL(adm_, SetAGC(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(true)).WillOnce(Return(0));
channel2->SetSend(true);
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
EXPECT_TRUE(ec_enabled);
EXPECT_FALSE(agc_enabled);
EXPECT_TRUE(ns_enabled);
// Make sure settings take effect while we are sending.
EXPECT_TRUE(channel_->SetSendParameters(parameters_options_all));
EXPECT_CALL(apm_, ApplyConfig(testing::_));
EXPECT_CALL(apm_, SetExtraOptions(testing::_));
cricket::AudioSendParameters parameters_options_no_agc_nor_ns =
send_parameters_;
parameters_options_no_agc_nor_ns.options.auto_gain_control =
rtc::Optional<bool>(false);
parameters_options_no_agc_nor_ns.options.noise_suppression =
rtc::Optional<bool>(false);
channel2->SetSend(true);
EXPECT_CALL(adm_, SetAGC(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, Enable(true)).WillOnce(Return(0));
EXPECT_CALL(apm_ec_, enable_metrics(true)).WillOnce(Return(0));
EXPECT_CALL(apm_gc_, Enable(false)).WillOnce(Return(0));
EXPECT_CALL(apm_ns_, Enable(false)).WillOnce(Return(0));
EXPECT_TRUE(channel2->SetSendParameters(parameters_options_no_agc_nor_ns));
expected_options.echo_cancellation = rtc::Optional<bool>(true);
expected_options.auto_gain_control = rtc::Optional<bool>(false);
expected_options.noise_suppression = rtc::Optional<bool>(false);
EXPECT_EQ(expected_options, channel2->options());
voe_.GetEcStatus(ec_enabled, ec_mode);
voe_.GetAgcStatus(agc_enabled, agc_mode);
voe_.GetNsStatus(ns_enabled, ns_mode);
EXPECT_TRUE(ec_enabled);
EXPECT_FALSE(agc_enabled);
EXPECT_FALSE(ns_enabled);
}
// This test verifies DSCP settings are properly applied on voice media channel.

View File

@ -44,6 +44,9 @@ namespace webrtc {
class AudioDeviceModule;
class AudioProcessing;
class AudioTransport;
namespace voe {
class TransmitMixer;
} // namespace voe
// VoiceEngineObserver
class WEBRTC_DLLEXPORT VoiceEngineObserver {
@ -143,6 +146,10 @@ class WEBRTC_DLLEXPORT VoEBase {
// Returns NULL before Init() is called.
virtual AudioDeviceModule* audio_device_module() = 0;
// This method is WIP - DO NOT USE!
// Returns NULL before Init() is called.
virtual voe::TransmitMixer* transmit_mixer() = 0;
// Terminates all VoiceEngine functions and releases allocated resources.
// Returns 0.
virtual int Terminate() = 0;

View File

@ -22,6 +22,7 @@ class AgcConfigTest : public AfterStreamingFixture {
webrtc::AgcConfig default_agc_config_;
};
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AgcConfigTest, HasCorrectDefaultConfiguration) {
webrtc::AgcConfig agc_config;
@ -33,6 +34,7 @@ TEST_F(AgcConfigTest, HasCorrectDefaultConfiguration) {
EXPECT_EQ(default_agc_config_.limiterEnable, agc_config.limiterEnable);
}
// Not needed anymore - we're not returning errors anymore, just logging.
TEST_F(AgcConfigTest, DealsWithInvalidParameters) {
webrtc::AgcConfig agc_config = default_agc_config_;
agc_config.digitalCompressionGaindB = 91;
@ -47,6 +49,7 @@ TEST_F(AgcConfigTest, DealsWithInvalidParameters) {
EXPECT_EQ(VE_APM_ERROR, voe_base_->LastError());
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AgcConfigTest, CanGetAndSetAgcStatus) {
webrtc::AgcConfig agc_config;
agc_config.digitalCompressionGaindB = 17;

View File

@ -13,6 +13,7 @@
class EcMetricsTest : public AfterStreamingFixture {
};
// Duplicated in apm_helpers_unittest.cc.
TEST_F(EcMetricsTest, EcMetricsAreOnByDefault) {
// AEC must be enabled fist.
EXPECT_EQ(0, voe_apm_->SetEcStatus(true, webrtc::kEcAec));
@ -22,6 +23,7 @@ TEST_F(EcMetricsTest, EcMetricsAreOnByDefault) {
EXPECT_TRUE(enabled);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(EcMetricsTest, CanEnableAndDisableEcMetrics) {
// AEC must be enabled fist.
EXPECT_EQ(0, voe_apm_->SetEcStatus(true, webrtc::kEcAec));
@ -35,6 +37,8 @@ TEST_F(EcMetricsTest, CanEnableAndDisableEcMetrics) {
ASSERT_FALSE(ec_on);
}
// TODO(solenberg): Do we have higher or lower level tests that verify metrics?
// It's not the right test for this level.
TEST_F(EcMetricsTest, ManualTestEcMetrics) {
SwitchToManualMicrophone();
@ -63,6 +67,7 @@ TEST_F(EcMetricsTest, ManualTestEcMetrics) {
EXPECT_EQ(0, voe_apm_->SetEcMetricsStatus(false));
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(EcMetricsTest, GetEcMetricsFailsIfEcNotEnabled) {
int dummy = 0;
EXPECT_EQ(0, voe_apm_->SetEcMetricsStatus(true));
@ -70,6 +75,7 @@ TEST_F(EcMetricsTest, GetEcMetricsFailsIfEcNotEnabled) {
EXPECT_EQ(VE_APM_ERROR, voe_base_->LastError());
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(EcMetricsTest, GetEcDelayMetricsFailsIfEcNotEnabled) {
int dummy = 0;
float dummy_f = 0;
@ -78,6 +84,8 @@ TEST_F(EcMetricsTest, GetEcDelayMetricsFailsIfEcNotEnabled) {
EXPECT_EQ(VE_APM_ERROR, voe_base_->LastError());
}
// TODO(solenberg): Do we have higher or lower level tests that verify metrics?
// It's not the right test for this level.
TEST_F(EcMetricsTest, ManualVerifyEcDelayMetrics) {
SwitchToManualMicrophone();
TEST_LOG("Verify EC Delay metrics:");

View File

@ -101,6 +101,7 @@ class AudioProcessingTest : public AfterStreamingFixture {
#if !defined(WEBRTC_IOS) && !defined(WEBRTC_ANDROID)
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, AgcIsOnByDefault) {
bool agc_enabled = false;
webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
@ -110,12 +111,14 @@ TEST_F(AudioProcessingTest, AgcIsOnByDefault) {
EXPECT_EQ(webrtc::kAgcAdaptiveAnalog, agc_mode);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, CanEnableAgcWithAllModes) {
TryEnablingAgcWithMode(webrtc::kAgcAdaptiveDigital);
TryEnablingAgcWithMode(webrtc::kAgcAdaptiveAnalog);
TryEnablingAgcWithMode(webrtc::kAgcFixedDigital);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, EcIsDisabledAndAecIsDefaultEcMode) {
bool ec_enabled = true;
webrtc::EcModes ec_mode = webrtc::kEcDefault;
@ -125,14 +128,17 @@ TEST_F(AudioProcessingTest, EcIsDisabledAndAecIsDefaultEcMode) {
EXPECT_EQ(webrtc::kEcAec, ec_mode);
}
// Not needed anymore - apm_helpers::SetEcStatus() doesn't take kEcAec.
TEST_F(AudioProcessingTest, EnablingEcAecShouldEnableEcAec) {
TryEnablingEcWithMode(webrtc::kEcAec, webrtc::kEcAec);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, EnablingEcConferenceShouldEnableEcAec) {
TryEnablingEcWithMode(webrtc::kEcConference, webrtc::kEcAec);
}
// Not needed anymore - apm_helpers::SetEcStatus() doesn't take kEcDefault.
TEST_F(AudioProcessingTest, EcModeIsPreservedWhenEcIsTurnedOff) {
TryEnablingEcWithMode(webrtc::kEcConference, webrtc::kEcAec);
@ -146,6 +152,7 @@ TEST_F(AudioProcessingTest, EcModeIsPreservedWhenEcIsTurnedOff) {
EXPECT_EQ(webrtc::kEcAec, ec_mode);
}
// Not needed anymore - apm_helpers::SetEcStatus() doesn't take kEcDefault.
TEST_F(AudioProcessingTest, CanEnableAndDisableEcModeSeveralTimesInARow) {
for (int i = 0; i < 10; i++) {
EXPECT_EQ(0, voe_apm_->SetEcStatus(true));
@ -162,11 +169,13 @@ TEST_F(AudioProcessingTest, CanEnableAndDisableEcModeSeveralTimesInARow) {
#endif // !WEBRTC_IOS && !WEBRTC_ANDROID
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, EnablingEcAecmShouldEnableEcAecm) {
// This one apparently applies to Android and iPhone as well.
TryEnablingEcWithMode(webrtc::kEcAecm, webrtc::kEcAecm);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, EcAecmModeIsEnabledAndSpeakerphoneByDefault) {
bool cng_enabled = false;
webrtc::AecmModes aecm_mode = webrtc::kAecmEarpiece;
@ -177,6 +186,7 @@ TEST_F(AudioProcessingTest, EcAecmModeIsEnabledAndSpeakerphoneByDefault) {
EXPECT_EQ(webrtc::kAecmSpeakerphone, aecm_mode);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, CanSetAecmMode) {
EXPECT_EQ(0, voe_apm_->SetEcStatus(true, webrtc::kEcAecm));
@ -189,6 +199,7 @@ TEST_F(AudioProcessingTest, CanSetAecmMode) {
TryEnablingAecmWithMode(webrtc::kAecmSpeakerphone, false);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, NsIsOffWithModerateSuppressionByDefault) {
bool ns_status = true;
webrtc::NsModes ns_mode = webrtc::kNsDefault;
@ -198,6 +209,7 @@ TEST_F(AudioProcessingTest, NsIsOffWithModerateSuppressionByDefault) {
EXPECT_EQ(webrtc::kNsModerateSuppression, ns_mode);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, CanSetNsMode) {
// Concrete suppression values map to themselves.
TryEnablingNsWithMode(webrtc::kNsHighSuppression,
@ -216,6 +228,8 @@ TEST_F(AudioProcessingTest, CanSetNsMode) {
webrtc::kNsModerateSuppression);
}
// TODO(solenberg): Duplicate this test at the voe::Channel layer.
// Not needed anymore - API is unused.
TEST_F(AudioProcessingTest, VadIsDisabledByDefault) {
bool vad_enabled;
bool disabled_dtx;
@ -227,6 +241,7 @@ TEST_F(AudioProcessingTest, VadIsDisabledByDefault) {
EXPECT_FALSE(vad_enabled);
}
// Not needed anymore - API is unused.
TEST_F(AudioProcessingTest, VoiceActivityIndicatorReturns1WithSpeechOn) {
// This sleep is necessary since the voice detection algorithm needs some
// time to detect the speech from the fake microphone.
@ -234,6 +249,7 @@ TEST_F(AudioProcessingTest, VoiceActivityIndicatorReturns1WithSpeechOn) {
EXPECT_EQ(1, voe_apm_->VoiceActivityIndicator(channel_));
}
// Not needed anymore - API is unused.
TEST_F(AudioProcessingTest, CanSetDelayOffset) {
voe_apm_->SetDelayOffsetMs(50);
EXPECT_EQ(50, voe_apm_->DelayOffsetMs());
@ -241,10 +257,13 @@ TEST_F(AudioProcessingTest, CanSetDelayOffset) {
EXPECT_EQ(-50, voe_apm_->DelayOffsetMs());
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, HighPassFilterIsOnByDefault) {
EXPECT_TRUE(voe_apm_->IsHighPassFilterEnabled());
}
// TODO(solenberg): Check that sufficient testing is done in APM.
// Not needed anymore - API is unused.
TEST_F(AudioProcessingTest, CanSetHighPassFilter) {
EXPECT_EQ(0, voe_apm_->EnableHighPassFilter(true));
EXPECT_TRUE(voe_apm_->IsHighPassFilterEnabled());
@ -252,10 +271,12 @@ TEST_F(AudioProcessingTest, CanSetHighPassFilter) {
EXPECT_FALSE(voe_apm_->IsHighPassFilterEnabled());
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, StereoChannelSwappingIsOffByDefault) {
EXPECT_FALSE(voe_apm_->IsStereoChannelSwappingEnabled());
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, CanSetStereoChannelSwapping) {
voe_apm_->EnableStereoChannelSwapping(true);
EXPECT_TRUE(voe_apm_->IsStereoChannelSwappingEnabled());
@ -263,6 +284,7 @@ TEST_F(AudioProcessingTest, CanSetStereoChannelSwapping) {
EXPECT_FALSE(voe_apm_->IsStereoChannelSwappingEnabled());
}
// TODO(solenberg): Check that sufficient testing is done in APM.
TEST_F(AudioProcessingTest, CanStartAndStopDebugRecording) {
std::string output_path = webrtc::test::OutputPath();
std::string output_file = output_path + "apm_debug.txt";
@ -274,6 +296,7 @@ TEST_F(AudioProcessingTest, CanStartAndStopDebugRecording) {
#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, AgcIsOffByDefaultAndDigital) {
bool agc_enabled = true;
webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
@ -283,16 +306,19 @@ TEST_F(AudioProcessingTest, AgcIsOffByDefaultAndDigital) {
EXPECT_EQ(webrtc::kAgcAdaptiveDigital, agc_mode);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, CanEnableAgcInAdaptiveDigitalMode) {
TryEnablingAgcWithMode(webrtc::kAgcAdaptiveDigital);
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, AgcIsPossibleExceptInAdaptiveAnalogMode) {
EXPECT_EQ(-1, voe_apm_->SetAgcStatus(true, webrtc::kAgcAdaptiveAnalog));
EXPECT_EQ(0, voe_apm_->SetAgcStatus(true, webrtc::kAgcFixedDigital));
EXPECT_EQ(0, voe_apm_->SetAgcStatus(true, webrtc::kAgcAdaptiveDigital));
}
// Duplicated in apm_helpers_unittest.cc.
TEST_F(AudioProcessingTest, EcIsDisabledAndAecmIsDefaultEcMode) {
bool ec_enabled = true;
webrtc::EcModes ec_mode = webrtc::kEcDefault;
@ -302,6 +328,7 @@ TEST_F(AudioProcessingTest, EcIsDisabledAndAecmIsDefaultEcMode) {
EXPECT_EQ(webrtc::kEcAecm, ec_mode);
}
// Not needed anymore - API is unused.
TEST_F(AudioProcessingTest, TestVoiceActivityDetection) {
TryDetectingSilence();
TryDetectingSpeechAfterSilence();

View File

@ -176,31 +176,12 @@ TransmitMixer::Destroy(TransmitMixer*& mixer)
}
TransmitMixer::TransmitMixer(uint32_t instanceId) :
_engineStatisticsPtr(NULL),
_channelManagerPtr(NULL),
audioproc_(NULL),
_voiceEngineObserverPtr(NULL),
_processThreadPtr(NULL),
// Avoid conflict with other channels by adding 1024 - 1026,
// won't use as much as 1024 channels.
_filePlayerId(instanceId + 1024),
_fileRecorderId(instanceId + 1025),
_fileCallRecorderId(instanceId + 1026),
_filePlaying(false),
_fileRecording(false),
_fileCallRecording(false),
_audioLevel(),
#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
_typingNoiseWarningPending(false),
_typingNoiseDetected(false),
#endif
_saturationWarning(false),
_instanceId(instanceId),
_mixFileWithMicrophone(false),
_captureLevel(0),
_mute(false),
stereo_codec_(false),
swap_stereo_channels_(false)
_instanceId(instanceId)
{
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, -1),
"TransmitMixer::TransmitMixer() - ctor");

View File

@ -138,15 +138,15 @@ public:
// FileCallback
void PlayNotification(int32_t id,
uint32_t durationMs);
void PlayNotification(const int32_t id,
const uint32_t durationMs);
void RecordNotification(int32_t id,
uint32_t durationMs);
void RecordNotification(const int32_t id,
const uint32_t durationMs);
void PlayFileEnded(int32_t id);
void PlayFileEnded(const int32_t id);
void RecordFileEnded(int32_t id);
void RecordFileEnded(const int32_t id);
#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
// Typing detection
@ -158,9 +158,13 @@ public:
int typeEventDelay);
#endif
void EnableStereoChannelSwapping(bool enable);
// Virtual to allow mocking.
virtual void EnableStereoChannelSwapping(bool enable);
bool IsStereoChannelSwappingEnabled();
protected:
TransmitMixer() = default;
private:
TransmitMixer(uint32_t instanceId);
@ -185,11 +189,11 @@ private:
#endif
// uses
Statistics* _engineStatisticsPtr;
ChannelManager* _channelManagerPtr;
AudioProcessing* audioproc_;
VoiceEngineObserver* _voiceEngineObserverPtr;
ProcessThread* _processThreadPtr;
Statistics* _engineStatisticsPtr = nullptr;
ChannelManager* _channelManagerPtr = nullptr;
AudioProcessing* audioproc_ = nullptr;
VoiceEngineObserver* _voiceEngineObserverPtr = nullptr;
ProcessThread* _processThreadPtr = nullptr;
// owns
MonitorModule _monitorModule;
@ -198,12 +202,12 @@ private:
std::unique_ptr<FilePlayer> file_player_;
std::unique_ptr<FileRecorder> file_recorder_;
std::unique_ptr<FileRecorder> file_call_recorder_;
int _filePlayerId;
int _fileRecorderId;
int _fileCallRecorderId;
bool _filePlaying;
bool _fileRecording;
bool _fileCallRecording;
int _filePlayerId = 0;
int _fileRecorderId = 0;
int _fileCallRecorderId = 0;
bool _filePlaying = false;
bool _fileRecording = false;
bool _fileCallRecording = false;
voe::AudioLevel _audioLevel;
// protect file instances and their variables in MixedParticipants()
rtc::CriticalSection _critSect;
@ -211,21 +215,19 @@ private:
#if WEBRTC_VOICE_ENGINE_TYPING_DETECTION
webrtc::TypingDetection _typingDetection;
bool _typingNoiseWarningPending;
bool _typingNoiseDetected;
bool _typingNoiseWarningPending = false;
bool _typingNoiseDetected = false;
#endif
bool _saturationWarning;
bool _saturationWarning = false;
int _instanceId;
bool _mixFileWithMicrophone;
uint32_t _captureLevel;
bool _mute;
bool stereo_codec_;
bool swap_stereo_channels_;
int _instanceId = 0;
bool _mixFileWithMicrophone = false;
uint32_t _captureLevel = 0;
bool _mute = false;
bool stereo_codec_ = false;
bool swap_stereo_channels_ = false;
};
} // namespace voe
} // namespace webrtc
#endif // WEBRTC_VOICE_ENGINE_TRANSMIT_MIXER_H

View File

@ -38,6 +38,9 @@ class VoEBaseImpl : public VoEBase,
AudioDeviceModule* audio_device_module() override {
return shared_->audio_device();
}
voe::TransmitMixer* transmit_mixer() override {
return shared_->transmit_mixer();
}
int Terminate() override;
int CreateChannel() override;