Add the network preference to RTCConfiguration.

The network preference is added to RTCConfiguration and passed to ICE.
ICE considers now the preference set by applications over network
interface types when making decisions in candidate pair switching.

Bug: webrtc:8816
Change-Id: I40d2612705b54c83dd45772ac855808e0a76b1e1
Reviewed-on: https://webrtc-review.googlesource.com/44020
Commit-Queue: Qingsi Wang <qingsi@google.com>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21855}
This commit is contained in:
Qingsi Wang
2018-02-01 10:38:40 -08:00
committed by Commit Bot
parent dc221515ff
commit 9a5c6f8f3f
11 changed files with 154 additions and 22 deletions

View File

@ -491,6 +491,12 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
// called. // called.
webrtc::TurnCustomizer* turn_customizer = nullptr; webrtc::TurnCustomizer* turn_customizer = nullptr;
// Preferred network interface.
// A candidate pair on a preferred network has a higher precedence in ICE
// than one on an un-preferred network, regardless of priority or network
// cost.
rtc::Optional<rtc::AdapterType> network_preference;
// Configure the SDP semantics used by this PeerConnection. Note that the // Configure the SDP semantics used by this PeerConnection. Note that the
// WebRTC 1.0 specification requires kUnifiedPlan semantics. The // WebRTC 1.0 specification requires kUnifiedPlan semantics. The
// RtpTransceiver API is only available with kUnifiedPlan semantics. // RtpTransceiver API is only available with kUnifiedPlan semantics.

View File

@ -21,7 +21,8 @@ IceConfig::IceConfig(int receiving_timeout_ms,
int stable_writable_connection_ping_interval_ms, int stable_writable_connection_ping_interval_ms,
bool presume_writable_when_fully_relayed, bool presume_writable_when_fully_relayed,
int regather_on_failed_networks_interval_ms, int regather_on_failed_networks_interval_ms,
int receiving_switching_delay_ms) int receiving_switching_delay_ms,
rtc::Optional<rtc::AdapterType> network_preference)
: receiving_timeout(receiving_timeout_ms), : receiving_timeout(receiving_timeout_ms),
backup_connection_ping_interval(backup_connection_ping_interval), backup_connection_ping_interval(backup_connection_ping_interval),
continual_gathering_policy(gathering_policy), continual_gathering_policy(gathering_policy),
@ -32,7 +33,8 @@ IceConfig::IceConfig(int receiving_timeout_ms,
presume_writable_when_fully_relayed(presume_writable_when_fully_relayed), presume_writable_when_fully_relayed(presume_writable_when_fully_relayed),
regather_on_failed_networks_interval( regather_on_failed_networks_interval(
regather_on_failed_networks_interval_ms), regather_on_failed_networks_interval_ms),
receiving_switching_delay(receiving_switching_delay_ms) {} receiving_switching_delay(receiving_switching_delay_ms),
network_preference(network_preference) {}
IceConfig::~IceConfig() = default; IceConfig::~IceConfig() = default;

View File

@ -115,6 +115,8 @@ struct IceConfig {
// Measure in milliseconds. // Measure in milliseconds.
rtc::Optional<int> ice_check_min_interval; rtc::Optional<int> ice_check_min_interval;
rtc::Optional<rtc::AdapterType> network_preference;
IceConfig(); IceConfig();
IceConfig(int receiving_timeout_ms, IceConfig(int receiving_timeout_ms,
int backup_connection_ping_interval, int backup_connection_ping_interval,
@ -123,7 +125,8 @@ struct IceConfig {
int stable_writable_connection_ping_interval_ms, int stable_writable_connection_ping_interval_ms,
bool presume_writable_when_fully_relayed, bool presume_writable_when_fully_relayed,
int regather_on_failed_networks_interval_ms, int regather_on_failed_networks_interval_ms,
int receiving_switching_delay_ms); int receiving_switching_delay_ms,
rtc::Optional<rtc::AdapterType> network_preference);
~IceConfig(); ~IceConfig();
}; };

View File

@ -61,6 +61,35 @@ cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port,
return cricket::PortInterface::ORIGIN_OTHER_PORT; return cricket::PortInterface::ORIGIN_OTHER_PORT;
} }
// TODO(qingsi) Use an enum to replace the following constants for all
// comparision results.
static constexpr int a_is_better = 1;
static constexpr int b_is_better = -1;
static constexpr int a_and_b_equal = 0;
bool LocalCandidateUsesPreferredNetwork(
const cricket::Connection* conn,
rtc::Optional<rtc::AdapterType> network_preference) {
rtc::AdapterType network_type = conn->port()->Network()->type();
return network_preference.has_value() && (network_type == network_preference);
}
int CompareCandidatePairsByNetworkPreference(
const cricket::Connection* a,
const cricket::Connection* b,
rtc::Optional<rtc::AdapterType> network_preference) {
bool a_uses_preferred_network =
LocalCandidateUsesPreferredNetwork(a, network_preference);
bool b_uses_preferred_network =
LocalCandidateUsesPreferredNetwork(b, network_preference);
if (a_uses_preferred_network && !b_uses_preferred_network) {
return a_is_better;
} else if (!a_uses_preferred_network && b_uses_preferred_network) {
return b_is_better;
}
return a_and_b_equal;
}
} // unnamed namespace } // unnamed namespace
namespace cricket { namespace cricket {
@ -98,9 +127,6 @@ static const int DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL = 5 * 60 * 1000;
static constexpr int DEFAULT_BACKUP_CONNECTION_PING_INTERVAL = 25 * 1000; static constexpr int DEFAULT_BACKUP_CONNECTION_PING_INTERVAL = 25 * 1000;
static constexpr int a_is_better = 1;
static constexpr int b_is_better = -1;
bool IceCredentialsChanged(const std::string& old_ufrag, bool IceCredentialsChanged(const std::string& old_ufrag,
const std::string& old_pwd, const std::string& old_pwd,
const std::string& new_ufrag, const std::string& new_ufrag,
@ -135,7 +161,8 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL, STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL,
true /* presume_writable_when_fully_relayed */, true /* presume_writable_when_fully_relayed */,
DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL, DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL,
RECEIVING_SWITCHING_DELAY) { RECEIVING_SWITCHING_DELAY,
rtc::nullopt) {
uint32_t weak_ping_interval = ::strtoul( uint32_t weak_ping_interval = ::strtoul(
webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(), webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(),
nullptr, 10); nullptr, 10);
@ -218,11 +245,12 @@ bool P2PTransportChannel::ShouldSwitchSelectedConnection(
return true; return true;
} }
// Do not switch to a connection that is not receiving if it has higher cost // Do not switch to a connection that is not receiving if it is not on a
// because it may be just spuriously better. // preferred network or it has higher cost because it may be just spuriously
if (new_connection->ComputeNetworkCost() > // better.
selected_connection_->ComputeNetworkCost() && int compare_a_b_by_networks = CompareCandidatePairNetworks(
!new_connection->receiving()) { new_connection, selected_connection_, config_.network_preference);
if (compare_a_b_by_networks == b_is_better && !new_connection->receiving()) {
return false; return false;
} }
@ -497,6 +525,14 @@ void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
RTC_LOG(LS_INFO) << "Set min ping interval to " RTC_LOG(LS_INFO) << "Set min ping interval to "
<< *config_.ice_check_min_interval; << *config_.ice_check_min_interval;
} }
if (config_.network_preference != config.network_preference) {
config_.network_preference = config.network_preference;
RTC_LOG(LS_INFO) << "Set network preference to "
<< (config_.network_preference.has_value()
? config_.network_preference.value()
: 0);
}
} }
const IceConfig& P2PTransportChannel::config() const { const IceConfig& P2PTransportChannel::config() const {
@ -1150,6 +1186,30 @@ void P2PTransportChannel::MaybeStartPinging() {
} }
} }
int P2PTransportChannel::CompareCandidatePairNetworks(
const Connection* a,
const Connection* b,
rtc::Optional<rtc::AdapterType> network_preference) const {
int compare_a_b_by_network_preference =
CompareCandidatePairsByNetworkPreference(a, b,
config_.network_preference);
// The network preference has a higher precedence than the network cost.
if (compare_a_b_by_network_preference != a_and_b_equal) {
return compare_a_b_by_network_preference;
}
uint32_t a_cost = a->ComputeNetworkCost();
uint32_t b_cost = b->ComputeNetworkCost();
// Prefer lower network cost.
if (a_cost < b_cost) {
return a_is_better;
}
if (a_cost > b_cost) {
return b_is_better;
}
return a_and_b_equal;
}
// Compare two connections based on their writing, receiving, and connected // Compare two connections based on their writing, receiving, and connected
// states. // states.
int P2PTransportChannel::CompareConnectionStates( int P2PTransportChannel::CompareConnectionStates(
@ -1230,15 +1290,10 @@ int P2PTransportChannel::CompareConnectionStates(
int P2PTransportChannel::CompareConnectionCandidates( int P2PTransportChannel::CompareConnectionCandidates(
const Connection* a, const Connection* a,
const Connection* b) const { const Connection* b) const {
// Prefer lower network cost. int compare_a_b_by_networks =
uint32_t a_cost = a->ComputeNetworkCost(); CompareCandidatePairNetworks(a, b, config_.network_preference);
uint32_t b_cost = b->ComputeNetworkCost(); if (compare_a_b_by_networks != a_and_b_equal) {
// Smaller cost is better. return compare_a_b_by_networks;
if (a_cost < b_cost) {
return a_is_better;
}
if (a_cost > b_cost) {
return b_is_better;
} }
// Compare connection priority. Lower values get sorted last. // Compare connection priority. Lower values get sorted last.

View File

@ -195,6 +195,11 @@ class P2PTransportChannel : public IceTransportInternal,
// that's pingable. // that's pingable.
void MaybeStartPinging(); void MaybeStartPinging();
int CompareCandidatePairNetworks(
const Connection* a,
const Connection* b,
rtc::Optional<rtc::AdapterType> network_preference) const;
// The methods below return a positive value if |a| is preferable to |b|, // The methods below return a positive value if |a| is preferable to |b|,
// a negative value if |b| is preferable, and 0 if they're equally preferable. // a negative value if |b| is preferable, and 0 if they're equally preferable.
// If |receiving_unchanged_threshold| is set, then when |b| is receiving and // If |receiving_unchanged_threshold| is set, then when |b| is receiving and

View File

@ -603,6 +603,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
rtc::Optional<rtc::IntervalRange> ice_regather_interval_range; rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
webrtc::TurnCustomizer* turn_customizer; webrtc::TurnCustomizer* turn_customizer;
SdpSemantics sdp_semantics; SdpSemantics sdp_semantics;
rtc::Optional<rtc::AdapterType> network_preference;
}; };
static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this), static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
"Did you add something to RTCConfiguration and forget to " "Did you add something to RTCConfiguration and forget to "
@ -639,7 +640,8 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
ice_check_min_interval == o.ice_check_min_interval && ice_check_min_interval == o.ice_check_min_interval &&
ice_regather_interval_range == o.ice_regather_interval_range && ice_regather_interval_range == o.ice_regather_interval_range &&
turn_customizer == o.turn_customizer && turn_customizer == o.turn_customizer &&
sdp_semantics == o.sdp_semantics; sdp_semantics == o.sdp_semantics &&
network_preference == o.network_preference;
} }
bool PeerConnectionInterface::RTCConfiguration::operator!=( bool PeerConnectionInterface::RTCConfiguration::operator!=(
@ -2519,6 +2521,7 @@ bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration,
modified_config.prune_turn_ports = configuration.prune_turn_ports; modified_config.prune_turn_ports = configuration.prune_turn_ports;
modified_config.ice_check_min_interval = configuration.ice_check_min_interval; modified_config.ice_check_min_interval = configuration.ice_check_min_interval;
modified_config.turn_customizer = configuration.turn_customizer; modified_config.turn_customizer = configuration.turn_customizer;
modified_config.network_preference = configuration.network_preference;
if (configuration != modified_config) { if (configuration != modified_config) {
RTC_LOG(LS_ERROR) << "Modifying the configuration in an unsupported way."; RTC_LOG(LS_ERROR) << "Modifying the configuration in an unsupported way.";
return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error); return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
@ -4613,6 +4616,7 @@ cricket::IceConfig PeerConnection::ParseIceConfig(
RTC_NOTREACHED(); RTC_NOTREACHED();
gathering_policy = cricket::GATHER_ONCE; gathering_policy = cricket::GATHER_ONCE;
} }
cricket::IceConfig ice_config; cricket::IceConfig ice_config;
ice_config.receiving_timeout = config.ice_connection_receiving_timeout; ice_config.receiving_timeout = config.ice_connection_receiving_timeout;
ice_config.prioritize_most_likely_candidate_pairs = ice_config.prioritize_most_likely_candidate_pairs =
@ -4625,6 +4629,7 @@ cricket::IceConfig PeerConnection::ParseIceConfig(
ice_config.ice_check_min_interval = config.ice_check_min_interval; ice_config.ice_check_min_interval = config.ice_check_min_interval;
ice_config.regather_all_networks_interval_range = ice_config.regather_all_networks_interval_range =
config.ice_regather_interval_range; config.ice_regather_interval_range;
ice_config.network_preference = config.network_preference;
return ice_config; return ice_config;
} }

View File

@ -304,6 +304,16 @@ public class PeerConnection {
/** Java version of PeerConnectionInterface.CandidateNetworkPolicy */ /** Java version of PeerConnectionInterface.CandidateNetworkPolicy */
public enum CandidateNetworkPolicy { ALL, LOW_COST } public enum CandidateNetworkPolicy { ALL, LOW_COST }
// Keep in sync with webrtc/rtc_base/network_constants.h.
public enum AdapterType {
UNKNOWN,
ETHERNET,
WIFI,
CELLULAR,
VPN,
LOOPBACK,
}
/** Java version of rtc::KeyType */ /** Java version of rtc::KeyType */
public enum KeyType { RSA, ECDSA } public enum KeyType { RSA, ECDSA }
@ -368,6 +378,9 @@ public class PeerConnection {
public Integer screencastMinBitrate; public Integer screencastMinBitrate;
public Boolean combinedAudioVideoBwe; public Boolean combinedAudioVideoBwe;
public Boolean enableDtlsSrtp; public Boolean enableDtlsSrtp;
// Use "Unknown" to represent no preference of adapter types, not the
// preference of adapters of unknown types.
public AdapterType networkPreference;
// This is an optional wrapper for the C++ webrtc::TurnCustomizer. // This is an optional wrapper for the C++ webrtc::TurnCustomizer.
public TurnCustomizer turnCustomizer; public TurnCustomizer turnCustomizer;
@ -403,6 +416,7 @@ public class PeerConnection {
screencastMinBitrate = null; screencastMinBitrate = null;
combinedAudioVideoBwe = null; combinedAudioVideoBwe = null;
enableDtlsSrtp = null; enableDtlsSrtp = null;
networkPreference = AdapterType.UNKNOWN;
} }
@CalledByNative("RTCConfiguration") @CalledByNative("RTCConfiguration")
@ -544,6 +558,11 @@ public class PeerConnection {
Boolean getEnableDtlsSrtp() { Boolean getEnableDtlsSrtp() {
return enableDtlsSrtp; return enableDtlsSrtp;
} }
@CalledByNative("RTCConfiguration")
AdapterType getNetworkPreference() {
return networkPreference;
}
}; };
private final List<MediaStream> localStreams = new ArrayList<>(); private final List<MediaStream> localStreams = new ArrayList<>();

View File

@ -95,6 +95,8 @@ public class PeerConnectionFactory {
public static class Options { public static class Options {
// Keep in sync with webrtc/rtc_base/network.h! // Keep in sync with webrtc/rtc_base/network.h!
//
// These bit fields are defined for |networkIgnoreMask| below.
static final int ADAPTER_TYPE_UNKNOWN = 0; static final int ADAPTER_TYPE_UNKNOWN = 0;
static final int ADAPTER_TYPE_ETHERNET = 1 << 0; static final int ADAPTER_TYPE_ETHERNET = 1 << 0;
static final int ADAPTER_TYPE_WIFI = 1 << 1; static final int ADAPTER_TYPE_WIFI = 1 << 1;

View File

@ -207,5 +207,32 @@ PeerConnectionInterface::TlsCertPolicy JavaToNativeTlsCertPolicy(
return PeerConnectionInterface::kTlsCertPolicySecure; return PeerConnectionInterface::kTlsCertPolicySecure;
} }
rtc::Optional<rtc::AdapterType> JavaToNativeNetworkPreference(
JNIEnv* jni,
const JavaRef<jobject>& j_network_preference) {
std::string enum_name = GetJavaEnumName(jni, j_network_preference);
if (enum_name == "UNKNOWN")
return rtc::nullopt;
if (enum_name == "ETHERNET")
return rtc::ADAPTER_TYPE_ETHERNET;
if (enum_name == "WIFI")
return rtc::ADAPTER_TYPE_WIFI;
if (enum_name == "CELLULAR")
return rtc::ADAPTER_TYPE_CELLULAR;
if (enum_name == "VPN")
return rtc::ADAPTER_TYPE_VPN;
if (enum_name == "LOOPBACK")
return rtc::ADAPTER_TYPE_LOOPBACK;
RTC_CHECK(false) << "Unexpected NetworkPreference enum_name " << enum_name;
return rtc::nullopt;
}
} // namespace jni } // namespace jni
} // namespace webrtc } // namespace webrtc

View File

@ -75,6 +75,10 @@ PeerConnectionInterface::TlsCertPolicy JavaToNativeTlsCertPolicy(
JNIEnv* jni, JNIEnv* jni,
const JavaRef<jobject>& j_ice_server_tls_cert_policy); const JavaRef<jobject>& j_ice_server_tls_cert_policy);
rtc::Optional<rtc::AdapterType> JavaToNativeNetworkPreference(
JNIEnv* jni,
const JavaRef<jobject>& j_network_preference);
} // namespace jni } // namespace jni
} // namespace webrtc } // namespace webrtc

View File

@ -121,6 +121,8 @@ void JavaToNativeRTCConfiguration(
Java_RTCConfiguration_getContinualGatheringPolicy(jni, j_rtc_config); Java_RTCConfiguration_getContinualGatheringPolicy(jni, j_rtc_config);
ScopedJavaLocalRef<jobject> j_turn_customizer = ScopedJavaLocalRef<jobject> j_turn_customizer =
Java_RTCConfiguration_getTurnCustomizer(jni, j_rtc_config); Java_RTCConfiguration_getTurnCustomizer(jni, j_rtc_config);
ScopedJavaLocalRef<jobject> j_network_preference =
Java_RTCConfiguration_getNetworkPreference(jni, j_rtc_config);
rtc_config->type = JavaToNativeIceTransportsType(jni, j_ice_transports_type); rtc_config->type = JavaToNativeIceTransportsType(jni, j_ice_transports_type);
rtc_config->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy); rtc_config->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy);
@ -184,6 +186,8 @@ void JavaToNativeRTCConfiguration(
jni, Java_RTCConfiguration_getCombinedAudioVideoBwe(jni, j_rtc_config)); jni, Java_RTCConfiguration_getCombinedAudioVideoBwe(jni, j_rtc_config));
rtc_config->enable_dtls_srtp = JavaToNativeOptionalBool( rtc_config->enable_dtls_srtp = JavaToNativeOptionalBool(
jni, Java_RTCConfiguration_getEnableDtlsSrtp(jni, j_rtc_config)); jni, Java_RTCConfiguration_getEnableDtlsSrtp(jni, j_rtc_config));
rtc_config->network_preference =
JavaToNativeNetworkPreference(jni, j_network_preference);
} }
rtc::KeyType GetRtcConfigKeyType(JNIEnv* env, rtc::KeyType GetRtcConfigKeyType(JNIEnv* env,