Add a flag to filter out high-cost networks.

This allows webrtc to not gather on cellular networks if wifi or
other low cost networks are present.
BUG=

Review-Url: https://codereview.webrtc.org/1987833002
Cr-Commit-Position: refs/heads/master@{#12979}
This commit is contained in:
honghaiz 2016-05-31 18:29:12 -07:00 committed by Commit bot
parent 8271a7f6d7
commit 603470576e
9 changed files with 121 additions and 0 deletions

View File

@ -83,6 +83,7 @@ ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
LoadClass(jni, "org/webrtc/PeerConnection$IceTransportsType");
LoadClass(jni, "org/webrtc/PeerConnection$TcpCandidatePolicy");
LoadClass(jni, "org/webrtc/PeerConnection$CandidateNetworkPolicy");
LoadClass(jni, "org/webrtc/PeerConnection$KeyType");
LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
LoadClass(jni, "org/webrtc/RtpReceiver");

View File

@ -1444,6 +1444,24 @@ JavaTcpCandidatePolicyToNativeType(
return PeerConnectionInterface::kTcpCandidatePolicyEnabled;
}
static PeerConnectionInterface::CandidateNetworkPolicy
JavaCandidateNetworkPolicyToNativeType(JNIEnv* jni,
jobject j_candidate_network_policy) {
std::string enum_name =
GetJavaEnumName(jni, "org/webrtc/PeerConnection$CandidateNetworkPolicy",
j_candidate_network_policy);
if (enum_name == "ALL")
return PeerConnectionInterface::kCandidateNetworkPolicyAll;
if (enum_name == "LOW_COST")
return PeerConnectionInterface::kCandidateNetworkPolicyLowCost;
RTC_CHECK(false) << "Unexpected CandidateNetworkPolicy enum_name "
<< enum_name;
return PeerConnectionInterface::kCandidateNetworkPolicyAll;
}
static rtc::KeyType JavaKeyTypeToNativeType(JNIEnv* jni, jobject j_key_type) {
std::string enum_name = GetJavaEnumName(
jni, "org/webrtc/PeerConnection$KeyType", j_key_type);
@ -1529,6 +1547,12 @@ static void JavaRTCConfigurationToJsepRTCConfiguration(
jobject j_tcp_candidate_policy = GetObjectField(
jni, j_rtc_config, j_tcp_candidate_policy_id);
jfieldID j_candidate_network_policy_id = GetFieldID(
jni, j_rtc_config_class, "candidateNetworkPolicy",
"Lorg/webrtc/PeerConnection$CandidateNetworkPolicy;");
jobject j_candidate_network_policy = GetObjectField(
jni, j_rtc_config, j_candidate_network_policy_id);
jfieldID j_ice_servers_id = GetFieldID(
jni, j_rtc_config_class, "iceServers", "Ljava/util/List;");
jobject j_ice_servers = GetObjectField(jni, j_rtc_config, j_ice_servers_id);
@ -1561,6 +1585,8 @@ static void JavaRTCConfigurationToJsepRTCConfiguration(
JavaRtcpMuxPolicyToNativeType(jni, j_rtcp_mux_policy);
rtc_config->tcp_candidate_policy =
JavaTcpCandidatePolicyToNativeType(jni, j_tcp_candidate_policy);
rtc_config->candidate_network_policy =
JavaCandidateNetworkPolicyToNativeType(jni, j_candidate_network_policy);
JavaIceServersToJsepIceServers(jni, j_ice_servers, &rtc_config->servers);
rtc_config->audio_jitter_buffer_max_packets =
GetIntField(jni, j_rtc_config, j_audio_jitter_buffer_max_packets_id);

View File

@ -116,6 +116,11 @@ public class PeerConnection {
ENABLED, DISABLED
};
/** Java version of PeerConnectionInterface.CandidateNetworkPolicy */
public enum CandidateNetworkPolicy {
ALL, LOW_COST
};
/** Java version of rtc::KeyType */
public enum KeyType {
RSA, ECDSA
@ -133,6 +138,7 @@ public class PeerConnection {
public BundlePolicy bundlePolicy;
public RtcpMuxPolicy rtcpMuxPolicy;
public TcpCandidatePolicy tcpCandidatePolicy;
public CandidateNetworkPolicy candidateNetworkPolicy;
public int audioJitterBufferMaxPackets;
public boolean audioJitterBufferFastAccelerate;
public int iceConnectionReceivingTimeout;
@ -146,6 +152,7 @@ public class PeerConnection {
bundlePolicy = BundlePolicy.BALANCED;
rtcpMuxPolicy = RtcpMuxPolicy.NEGOTIATE;
tcpCandidatePolicy = TcpCandidatePolicy.ENABLED;
candidateNetworkPolicy = candidateNetworkPolicy.ALL;
this.iceServers = iceServers;
audioJitterBufferMaxPackets = 50;
audioJitterBufferFastAccelerate = false;

View File

@ -2128,6 +2128,12 @@ bool PeerConnection::InitializePortAllocator_n(
LOG(LS_INFO) << "TCP candidates are disabled.";
}
if (configuration.candidate_network_policy ==
kCandidateNetworkPolicyLowCost) {
portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_COSTLY_NETWORKS;
LOG(LS_INFO) << "Do not gather candidates on high-cost networks";
}
port_allocator_->set_flags(portallocator_flags);
// No step delay is used while allocating ports.
port_allocator_->set_step_delay(cricket::kMinimumStepDelay);

View File

@ -217,6 +217,11 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
kTcpCandidatePolicyDisabled
};
enum CandidateNetworkPolicy {
kCandidateNetworkPolicyAll,
kCandidateNetworkPolicyLowCost
};
enum ContinualGatheringPolicy {
GATHER_ONCE,
GATHER_CONTINUALLY
@ -276,6 +281,8 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
BundlePolicy bundle_policy = kBundlePolicyBalanced;
RtcpMuxPolicy rtcp_mux_policy = kRtcpMuxPolicyNegotiate;
TcpCandidatePolicy tcp_candidate_policy = kTcpCandidatePolicyEnabled;
CandidateNetworkPolicy candidate_network_policy =
kCandidateNetworkPolicyAll;
int audio_jitter_buffer_max_packets = kAudioJitterBufferMaxPackets;
bool audio_jitter_buffer_fast_accelerate = false;
int ice_connection_receiving_timeout = kUndefined; // ms

View File

@ -1050,6 +1050,8 @@ TEST_F(PeerConnectionInterfaceTest, CreatePeerConnectionWithPooledCandidates) {
config.disable_ipv6 = true;
config.tcp_candidate_policy =
PeerConnectionInterface::kTcpCandidatePolicyDisabled;
config.candidate_network_policy =
PeerConnectionInterface::kCandidateNetworkPolicyLowCost;
config.ice_candidate_pool_size = 1;
CreatePeerConnection(config, nullptr);
@ -1060,6 +1062,8 @@ TEST_F(PeerConnectionInterfaceTest, CreatePeerConnectionWithPooledCandidates) {
EXPECT_EQ(1UL, session->stun_servers().size());
EXPECT_EQ(0U, session->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6);
EXPECT_LT(0U, session->flags() & cricket::PORTALLOCATOR_DISABLE_TCP);
EXPECT_LT(0U,
session->flags() & cricket::PORTALLOCATOR_DISABLE_COSTLY_NETWORKS);
}
TEST_F(PeerConnectionInterfaceTest, AddStreams) {

View File

@ -60,6 +60,16 @@ enum {
// Disallow use of UDP when connecting to a relay server. Since proxy servers
// usually don't handle UDP, using UDP will leak the IP address.
PORTALLOCATOR_DISABLE_UDP_RELAY = 0x1000,
// When multiple networks exist, do not gather candidates on the ones with
// high cost. So if both Wi-Fi and cellular networks exist, gather only on the
// Wi-Fi network. If a network type is "unknown", it has a cost lower than
// cellular but higher than Wi-Fi/Ethernet. So if an unknown network exists,
// cellular networks will not be used to gather candidates and if a Wi-Fi
// network is present, "unknown" networks will not be usd to gather
// candidates. Doing so ensures that even if a cellular network type was not
// detected initially, it would not be used if a Wi-Fi network is present.
PORTALLOCATOR_DISABLE_COSTLY_NETWORKS = 0x2000,
};
const uint32_t kDefaultPortAllocatorFlags = 0;

View File

@ -417,6 +417,19 @@ void BasicPortAllocatorSession::GetNetworks(
network->type();
}),
networks->end());
if (flags() & PORTALLOCATOR_DISABLE_COSTLY_NETWORKS) {
uint16_t lowest_cost = rtc::kNetworkCostMax;
for (rtc::Network* network : *networks) {
lowest_cost = std::min<uint16_t>(lowest_cost, network->GetCost());
}
networks->erase(std::remove_if(networks->begin(), networks->end(),
[lowest_cost](rtc::Network* network) {
return network->GetCost() >
lowest_cost + rtc::kNetworkCostLow;
}),
networks->end());
}
}
// For each network, see if we have a sequence that covers it already. If not,

View File

@ -519,6 +519,53 @@ TEST_F(BasicPortAllocatorTest, TestIgnoreNetworksAccordingToIgnoreMask) {
EXPECT_EQ(0x12345602U, candidates_[0].address().ip());
}
// Test that high cost networks are filtered if the flag
// PORTALLOCATOR_DISABLE_COSTLY_NETWORKS is set.
TEST_F(BasicPortAllocatorTest, TestGatherLowCostNetworkOnly) {
SocketAddress addr_wifi(IPAddress(0x12345600U), 0);
SocketAddress addr_cellular(IPAddress(0x12345601U), 0);
SocketAddress addr_unknown1(IPAddress(0x12345602U), 0);
SocketAddress addr_unknown2(IPAddress(0x12345603U), 0);
// If both Wi-Fi and cellular interfaces are present, only gather on the Wi-Fi
// interface.
AddInterface(addr_wifi, "test_wlan0", rtc::ADAPTER_TYPE_WIFI);
AddInterface(addr_cellular, "test_cell0", rtc::ADAPTER_TYPE_CELLULAR);
allocator().set_flags(cricket::PORTALLOCATOR_DISABLE_STUN |
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_DISABLE_TCP |
cricket::PORTALLOCATOR_DISABLE_COSTLY_NETWORKS);
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
EXPECT_EQ(1U, candidates_.size());
EXPECT_TRUE(addr_wifi.EqualIPs(candidates_[0].address()));
// If both cellular and unknown interfaces are present, only gather on the
// unknown interfaces.
candidates_.clear();
candidate_allocation_done_ = false;
RemoveInterface(addr_wifi);
AddInterface(addr_unknown1, "test_unknown0", rtc::ADAPTER_TYPE_UNKNOWN);
AddInterface(addr_unknown2, "test_unknown1", rtc::ADAPTER_TYPE_UNKNOWN);
session_->StartGettingPorts();
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
EXPECT_EQ(2U, candidates_.size());
EXPECT_TRUE((addr_unknown1.EqualIPs(candidates_[0].address()) &&
addr_unknown2.EqualIPs(candidates_[1].address())) ||
(addr_unknown1.EqualIPs(candidates_[1].address()) &&
addr_unknown2.EqualIPs(candidates_[0].address())));
// If Wi-Fi, cellular, unknown interfaces are all present, only gather on the
// Wi-Fi interface.
candidates_.clear();
candidate_allocation_done_ = false;
AddInterface(addr_wifi, "test_wlan0", rtc::ADAPTER_TYPE_WIFI);
session_->StartGettingPorts();
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
EXPECT_EQ(1U, candidates_.size());
EXPECT_TRUE(addr_wifi.EqualIPs(candidates_[0].address()));
}
// Tests that we allocator session not trying to allocate ports for every 250ms.
TEST_F(BasicPortAllocatorTest, TestNoNetworkInterface) {
EXPECT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));