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:
@ -491,6 +491,12 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
|
||||
// called.
|
||||
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
|
||||
// WebRTC 1.0 specification requires kUnifiedPlan semantics. The
|
||||
// RtpTransceiver API is only available with kUnifiedPlan semantics.
|
||||
|
||||
@ -21,7 +21,8 @@ IceConfig::IceConfig(int receiving_timeout_ms,
|
||||
int stable_writable_connection_ping_interval_ms,
|
||||
bool presume_writable_when_fully_relayed,
|
||||
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),
|
||||
backup_connection_ping_interval(backup_connection_ping_interval),
|
||||
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),
|
||||
regather_on_failed_networks_interval(
|
||||
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;
|
||||
|
||||
|
||||
@ -115,6 +115,8 @@ struct IceConfig {
|
||||
// Measure in milliseconds.
|
||||
rtc::Optional<int> ice_check_min_interval;
|
||||
|
||||
rtc::Optional<rtc::AdapterType> network_preference;
|
||||
|
||||
IceConfig();
|
||||
IceConfig(int receiving_timeout_ms,
|
||||
int backup_connection_ping_interval,
|
||||
@ -123,7 +125,8 @@ struct IceConfig {
|
||||
int stable_writable_connection_ping_interval_ms,
|
||||
bool presume_writable_when_fully_relayed,
|
||||
int regather_on_failed_networks_interval_ms,
|
||||
int receiving_switching_delay_ms);
|
||||
int receiving_switching_delay_ms,
|
||||
rtc::Optional<rtc::AdapterType> network_preference);
|
||||
~IceConfig();
|
||||
};
|
||||
|
||||
|
||||
@ -61,6 +61,35 @@ cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* 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
|
||||
|
||||
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 a_is_better = 1;
|
||||
static constexpr int b_is_better = -1;
|
||||
|
||||
bool IceCredentialsChanged(const std::string& old_ufrag,
|
||||
const std::string& old_pwd,
|
||||
const std::string& new_ufrag,
|
||||
@ -135,7 +161,8 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
|
||||
STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL,
|
||||
true /* presume_writable_when_fully_relayed */,
|
||||
DEFAULT_REGATHER_ON_FAILED_NETWORKS_INTERVAL,
|
||||
RECEIVING_SWITCHING_DELAY) {
|
||||
RECEIVING_SWITCHING_DELAY,
|
||||
rtc::nullopt) {
|
||||
uint32_t weak_ping_interval = ::strtoul(
|
||||
webrtc::field_trial::FindFullName("WebRTC-StunInterPacketDelay").c_str(),
|
||||
nullptr, 10);
|
||||
@ -218,11 +245,12 @@ bool P2PTransportChannel::ShouldSwitchSelectedConnection(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do not switch to a connection that is not receiving if it has higher cost
|
||||
// because it may be just spuriously better.
|
||||
if (new_connection->ComputeNetworkCost() >
|
||||
selected_connection_->ComputeNetworkCost() &&
|
||||
!new_connection->receiving()) {
|
||||
// Do not switch to a connection that is not receiving if it is not on a
|
||||
// preferred network or it has higher cost because it may be just spuriously
|
||||
// better.
|
||||
int compare_a_b_by_networks = CompareCandidatePairNetworks(
|
||||
new_connection, selected_connection_, config_.network_preference);
|
||||
if (compare_a_b_by_networks == b_is_better && !new_connection->receiving()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -497,6 +525,14 @@ void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
|
||||
RTC_LOG(LS_INFO) << "Set min ping interval to "
|
||||
<< *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 {
|
||||
@ -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
|
||||
// states.
|
||||
int P2PTransportChannel::CompareConnectionStates(
|
||||
@ -1230,15 +1290,10 @@ int P2PTransportChannel::CompareConnectionStates(
|
||||
int P2PTransportChannel::CompareConnectionCandidates(
|
||||
const Connection* a,
|
||||
const Connection* b) const {
|
||||
// Prefer lower network cost.
|
||||
uint32_t a_cost = a->ComputeNetworkCost();
|
||||
uint32_t b_cost = b->ComputeNetworkCost();
|
||||
// Smaller cost is better.
|
||||
if (a_cost < b_cost) {
|
||||
return a_is_better;
|
||||
}
|
||||
if (a_cost > b_cost) {
|
||||
return b_is_better;
|
||||
int compare_a_b_by_networks =
|
||||
CompareCandidatePairNetworks(a, b, config_.network_preference);
|
||||
if (compare_a_b_by_networks != a_and_b_equal) {
|
||||
return compare_a_b_by_networks;
|
||||
}
|
||||
|
||||
// Compare connection priority. Lower values get sorted last.
|
||||
|
||||
@ -195,6 +195,11 @@ class P2PTransportChannel : public IceTransportInternal,
|
||||
// that's pingable.
|
||||
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|,
|
||||
// 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
|
||||
|
||||
@ -603,6 +603,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
|
||||
webrtc::TurnCustomizer* turn_customizer;
|
||||
SdpSemantics sdp_semantics;
|
||||
rtc::Optional<rtc::AdapterType> network_preference;
|
||||
};
|
||||
static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
|
||||
"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_regather_interval_range == o.ice_regather_interval_range &&
|
||||
turn_customizer == o.turn_customizer &&
|
||||
sdp_semantics == o.sdp_semantics;
|
||||
sdp_semantics == o.sdp_semantics &&
|
||||
network_preference == o.network_preference;
|
||||
}
|
||||
|
||||
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.ice_check_min_interval = configuration.ice_check_min_interval;
|
||||
modified_config.turn_customizer = configuration.turn_customizer;
|
||||
modified_config.network_preference = configuration.network_preference;
|
||||
if (configuration != modified_config) {
|
||||
RTC_LOG(LS_ERROR) << "Modifying the configuration in an unsupported way.";
|
||||
return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
|
||||
@ -4613,6 +4616,7 @@ cricket::IceConfig PeerConnection::ParseIceConfig(
|
||||
RTC_NOTREACHED();
|
||||
gathering_policy = cricket::GATHER_ONCE;
|
||||
}
|
||||
|
||||
cricket::IceConfig ice_config;
|
||||
ice_config.receiving_timeout = config.ice_connection_receiving_timeout;
|
||||
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.regather_all_networks_interval_range =
|
||||
config.ice_regather_interval_range;
|
||||
ice_config.network_preference = config.network_preference;
|
||||
return ice_config;
|
||||
}
|
||||
|
||||
|
||||
@ -304,6 +304,16 @@ public class PeerConnection {
|
||||
/** Java version of PeerConnectionInterface.CandidateNetworkPolicy */
|
||||
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 */
|
||||
public enum KeyType { RSA, ECDSA }
|
||||
|
||||
@ -368,6 +378,9 @@ public class PeerConnection {
|
||||
public Integer screencastMinBitrate;
|
||||
public Boolean combinedAudioVideoBwe;
|
||||
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.
|
||||
public TurnCustomizer turnCustomizer;
|
||||
@ -403,6 +416,7 @@ public class PeerConnection {
|
||||
screencastMinBitrate = null;
|
||||
combinedAudioVideoBwe = null;
|
||||
enableDtlsSrtp = null;
|
||||
networkPreference = AdapterType.UNKNOWN;
|
||||
}
|
||||
|
||||
@CalledByNative("RTCConfiguration")
|
||||
@ -544,6 +558,11 @@ public class PeerConnection {
|
||||
Boolean getEnableDtlsSrtp() {
|
||||
return enableDtlsSrtp;
|
||||
}
|
||||
|
||||
@CalledByNative("RTCConfiguration")
|
||||
AdapterType getNetworkPreference() {
|
||||
return networkPreference;
|
||||
}
|
||||
};
|
||||
|
||||
private final List<MediaStream> localStreams = new ArrayList<>();
|
||||
|
||||
@ -95,6 +95,8 @@ public class PeerConnectionFactory {
|
||||
|
||||
public static class Options {
|
||||
// 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_ETHERNET = 1 << 0;
|
||||
static final int ADAPTER_TYPE_WIFI = 1 << 1;
|
||||
|
||||
@ -207,5 +207,32 @@ PeerConnectionInterface::TlsCertPolicy JavaToNativeTlsCertPolicy(
|
||||
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 webrtc
|
||||
|
||||
@ -75,6 +75,10 @@ PeerConnectionInterface::TlsCertPolicy JavaToNativeTlsCertPolicy(
|
||||
JNIEnv* jni,
|
||||
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 webrtc
|
||||
|
||||
|
||||
@ -121,6 +121,8 @@ void JavaToNativeRTCConfiguration(
|
||||
Java_RTCConfiguration_getContinualGatheringPolicy(jni, j_rtc_config);
|
||||
ScopedJavaLocalRef<jobject> j_turn_customizer =
|
||||
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->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy);
|
||||
@ -184,6 +186,8 @@ void JavaToNativeRTCConfiguration(
|
||||
jni, Java_RTCConfiguration_getCombinedAudioVideoBwe(jni, j_rtc_config));
|
||||
rtc_config->enable_dtls_srtp = JavaToNativeOptionalBool(
|
||||
jni, Java_RTCConfiguration_getEnableDtlsSrtp(jni, j_rtc_config));
|
||||
rtc_config->network_preference =
|
||||
JavaToNativeNetworkPreference(jni, j_network_preference);
|
||||
}
|
||||
|
||||
rtc::KeyType GetRtcConfigKeyType(JNIEnv* env,
|
||||
|
||||
Reference in New Issue
Block a user