Add configurable connectivity check intervals.
The connectivity check intervals for candidate pairs with strong and
weak connectivity are currently constants in the ICE implementation. A
set of suboptimal value of these constants for a given application may
result in undesirable behavior including excessive network switching
latency. This CL adds these intervals to RTCConfiguration that is
available to applications to configure, while maintaining the original
constants as their default value for compatibility with existing
applications.
Bug: webrtc:8988
Change-Id: I804b0f4cf7881be7d3c8aec2776bc9596de72482
Reviewed-on: https://webrtc-review.googlesource.com/60585
Commit-Queue: Qingsi Wang <qingsi@google.com>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22351}
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index 1dfe2bd..7364aa0 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -489,8 +489,30 @@
// re-determining was removed in ICEbis (ICE v2).
bool redetermine_role_on_ice_restart = true;
- // If set, the min interval (max rate) at which we will send ICE checks
- // (STUN pings), in milliseconds.
+ // The following fields define intervals in milliseconds at which ICE
+ // connectivity checks are sent.
+ //
+ // We consider ICE is "strongly connected" for an agent when there is at
+ // least one candidate pair that currently succeeds in connectivity check
+ // from its direction i.e. sending a STUN ping and receives a STUN ping
+ // response, AND all candidate pairs have sent a minimum number of pings for
+ // connectivity (this number is implementation-specific). Otherwise, ICE is
+ // considered in "weak connectivity".
+ //
+ // Note that the above notion of strong and weak connectivity is not defined
+ // in RFC 5245, and they apply to our current ICE implementation only.
+ //
+ // 1) ice_check_interval_strong_connectivity defines the interval applied to
+ // ALL candidate pairs when ICE is strongly connected, and it overrides the
+ // default value of this interval in the ICE implementation;
+ // 2) ice_check_interval_weak_connectivity defines the counterpart for ALL
+ // pairs when ICE is weakly connected, and it overrides the default value of
+ // this interval in the ICE implementation;
+ // 3) ice_check_min_interval defines the minimal interval (equivalently the
+ // maximum rate) that overrides the above two intervals when either of them
+ // is less.
+ rtc::Optional<int> ice_check_interval_strong_connectivity;
+ rtc::Optional<int> ice_check_interval_weak_connectivity;
rtc::Optional<int> ice_check_min_interval;
// The interval in milliseconds at which STUN candidates will resend STUN
diff --git a/p2p/base/icetransportinternal.h b/p2p/base/icetransportinternal.h
index 192a9d0..a111f44 100644
--- a/p2p/base/icetransportinternal.h
+++ b/p2p/base/icetransportinternal.h
@@ -110,9 +110,23 @@
// Default nomination mode if the remote does not support renomination.
NominationMode default_nomination_mode = NominationMode::SEMI_AGGRESSIVE;
+ // The interval in milliseconds at which ICE checks (STUN pings) will be sent
+ // for a candidate pair when it is both writable and receiving (strong
+ // connectivity). This parameter overrides the default value given by
+ // |STRONG_PING_INTERVAL| in p2ptransport.h if set.
+ rtc::Optional<int> ice_check_interval_strong_connectivity;
+ // The interval in milliseconds at which ICE checks (STUN pings) will be sent
+ // for a candidate pair when it is either not writable or not receiving (weak
+ // connectivity). This parameter overrides the default value given by
+ // |WEAK_PING_INTERVAL| in p2ptransport.h if set.
+ rtc::Optional<int> ice_check_interval_weak_connectivity;
// ICE checks (STUN pings) will not be sent at higher rate (lower interval)
// than this, no matter what other settings there are.
// Measure in milliseconds.
+ //
+ // Note that this parameter overrides both the above check intervals for
+ // candidate pairs with strong or weak connectivity, if either of the above
+ // interval is shorter than the min interval.
rtc::Optional<int> ice_check_min_interval;
// The interval in milliseconds at which STUN candidates will resend STUN
// binding requests to keep NAT bindings open.
diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc
index b728334..5384801 100644
--- a/p2p/base/p2ptransportchannel.cc
+++ b/p2p/base/p2ptransportchannel.cc
@@ -105,9 +105,15 @@
// The next two ping intervals are at the channel level.
// STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both
// writable and receiving.
+//
+// This constant is the default value of ice_check_interval_strong_connectivity
+// in IceConfig if not set.
const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000;
// WEAK_PING_INTERVAL (48ms) is applied when the selected connection is either
// not writable or not receiving.
+//
+// This constant is the default value of ice_check_interval_weak_connectivity in
+// IceConfig if not set.
const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000;
// The next two ping intervals are at the connection level.
@@ -438,6 +444,11 @@
remote_ice_mode_ = mode;
}
+// TODO(qingsi): We apply the convention that setting a rtc::Optional parameter
+// to null restores its default value in the implementation. However, some
+// rtc::Optional parameters are only processed below if non-null, e.g.,
+// regather_on_failed_networks_interval, and thus there is no way to restore the
+// defaults. Fix this issue later for consistency.
void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
if (config_.continual_gathering_policy != config.continual_gathering_policy) {
if (!allocator_sessions_.empty()) {
@@ -504,7 +515,8 @@
config_.regather_on_failed_networks_interval =
config.regather_on_failed_networks_interval;
RTC_LOG(LS_INFO) << "Set regather_on_failed_networks_interval to "
- << *config_.regather_on_failed_networks_interval;
+ << config_.regather_on_failed_networks_interval.value_or(
+ -1);
}
if (config.regather_all_networks_interval_range) {
@@ -513,13 +525,15 @@
config_.regather_all_networks_interval_range =
config.regather_all_networks_interval_range;
RTC_LOG(LS_INFO) << "Set regather_all_networks_interval_range to "
- << config.regather_all_networks_interval_range->ToString();
+ << config.regather_all_networks_interval_range
+ .value_or(rtc::IntervalRange(-1, 0))
+ .ToString();
}
if (config.receiving_switching_delay) {
config_.receiving_switching_delay = config.receiving_switching_delay;
RTC_LOG(LS_INFO) << "Set receiving_switching_delay to"
- << *config_.receiving_switching_delay;
+ << config_.receiving_switching_delay.value_or(-1);
}
if (config_.default_nomination_mode != config.default_nomination_mode) {
@@ -528,10 +542,28 @@
<< static_cast<int>(config_.default_nomination_mode);
}
+ if (config_.ice_check_interval_strong_connectivity !=
+ config.ice_check_interval_strong_connectivity) {
+ config_.ice_check_interval_strong_connectivity =
+ config.ice_check_interval_strong_connectivity;
+ RTC_LOG(LS_INFO) << "Set strong ping interval to "
+ << config_.ice_check_interval_strong_connectivity.value_or(
+ -1);
+ }
+
+ if (config_.ice_check_interval_weak_connectivity !=
+ config.ice_check_interval_weak_connectivity) {
+ config_.ice_check_interval_weak_connectivity =
+ config.ice_check_interval_weak_connectivity;
+ RTC_LOG(LS_INFO) << "Set weak ping interval to "
+ << config_.ice_check_interval_weak_connectivity.value_or(
+ -1);
+ }
+
if (config_.ice_check_min_interval != config.ice_check_min_interval) {
config_.ice_check_min_interval = config.ice_check_min_interval;
RTC_LOG(LS_INFO) << "Set min ping interval to "
- << *config_.ice_check_min_interval;
+ << config_.ice_check_min_interval.value_or(-1);
}
if (config_.network_preference != config.network_preference) {
@@ -540,7 +572,8 @@
RTC_LOG(LS_INFO) << "Set network preference to "
<< (config_.network_preference.has_value()
? config_.network_preference.value()
- : 0);
+ : -1); // network_preference cannot be bound to
+ // int with value_or.
}
// TODO(qingsi): Resolve the naming conflict of stun_keepalive_delay in
@@ -550,9 +583,7 @@
allocator_session()->SetStunKeepaliveIntervalForReadyPorts(
config_.stun_keepalive_interval);
RTC_LOG(LS_INFO) << "Set STUN keepalive interval to "
- << (config.stun_keepalive_interval.has_value()
- ? config_.stun_keepalive_interval.value()
- : -1);
+ << config.stun_keepalive_interval.value_or(-1);
}
}
diff --git a/p2p/base/p2ptransportchannel.h b/p2p/base/p2ptransportchannel.h
index e4db38c..a9825cf 100644
--- a/p2p/base/p2ptransportchannel.h
+++ b/p2p/base/p2ptransportchannel.h
@@ -20,6 +20,7 @@
#ifndef P2P_BASE_P2PTRANSPORTCHANNEL_H_
#define P2P_BASE_P2PTRANSPORTCHANNEL_H_
+#include <algorithm>
#include <map>
#include <memory>
#include <set>
@@ -180,19 +181,15 @@
bool weak() const;
int weak_ping_interval() const {
- if (config_.ice_check_min_interval &&
- weak_ping_interval_ < *config_.ice_check_min_interval) {
- return *config_.ice_check_min_interval;
- }
- return weak_ping_interval_;
+ return std::max(config_.ice_check_interval_weak_connectivity.value_or(
+ weak_ping_interval_),
+ config_.ice_check_min_interval.value_or(-1));
}
int strong_ping_interval() const {
- if (config_.ice_check_min_interval &&
- STRONG_PING_INTERVAL < *config_.ice_check_min_interval) {
- return *config_.ice_check_min_interval;
- }
- return STRONG_PING_INTERVAL;
+ return std::max(config_.ice_check_interval_strong_connectivity.value_or(
+ STRONG_PING_INTERVAL),
+ config_.ice_check_min_interval.value_or(-1));
}
// Returns true if it's possible to send packets on |connection|.
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 3df7ebf..e37d9d8 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -663,6 +663,8 @@
bool presume_writable_when_fully_relayed;
bool enable_ice_renomination;
bool redetermine_role_on_ice_restart;
+ rtc::Optional<int> ice_check_interval_strong_connectivity;
+ rtc::Optional<int> ice_check_interval_weak_connectivity;
rtc::Optional<int> ice_check_min_interval;
rtc::Optional<int> stun_candidate_keepalive_interval;
rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
@@ -703,6 +705,10 @@
o.presume_writable_when_fully_relayed &&
enable_ice_renomination == o.enable_ice_renomination &&
redetermine_role_on_ice_restart == o.redetermine_role_on_ice_restart &&
+ ice_check_interval_strong_connectivity ==
+ o.ice_check_interval_strong_connectivity &&
+ ice_check_interval_weak_connectivity ==
+ o.ice_check_interval_weak_connectivity &&
ice_check_min_interval == o.ice_check_min_interval &&
stun_candidate_keepalive_interval ==
o.stun_candidate_keepalive_interval &&
@@ -2700,6 +2706,10 @@
configuration.ice_candidate_pool_size;
modified_config.prune_turn_ports = configuration.prune_turn_ports;
modified_config.ice_check_min_interval = configuration.ice_check_min_interval;
+ modified_config.ice_check_interval_strong_connectivity =
+ configuration.ice_check_interval_strong_connectivity;
+ modified_config.ice_check_interval_weak_connectivity =
+ configuration.ice_check_interval_weak_connectivity;
modified_config.stun_candidate_keepalive_interval =
configuration.stun_candidate_keepalive_interval;
modified_config.turn_customizer = configuration.turn_customizer;
@@ -4860,6 +4870,10 @@
ice_config.continual_gathering_policy = gathering_policy;
ice_config.presume_writable_when_fully_relayed =
config.presume_writable_when_fully_relayed;
+ ice_config.ice_check_interval_strong_connectivity =
+ config.ice_check_interval_strong_connectivity;
+ ice_config.ice_check_interval_weak_connectivity =
+ config.ice_check_interval_weak_connectivity;
ice_config.ice_check_min_interval = config.ice_check_min_interval;
ice_config.stun_keepalive_interval = config.stun_candidate_keepalive_interval;
ice_config.regather_all_networks_interval_range =
diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java
index 603b36e..65aa734 100644
--- a/sdk/android/api/org/webrtc/PeerConnection.java
+++ b/sdk/android/api/org/webrtc/PeerConnection.java
@@ -386,6 +386,28 @@
public int iceCandidatePoolSize;
public boolean pruneTurnPorts;
public boolean presumeWritableWhenFullyRelayed;
+ // The following fields define intervals in milliseconds at which ICE
+ // connectivity checks are sent.
+ //
+ // We consider ICE is "strongly connected" for an agent when there is at
+ // least one candidate pair that currently succeeds in connectivity check
+ // from its direction i.e. sending a ping and receives a ping response, AND
+ // all candidate pairs have sent a minimum number of pings for connectivity
+ // (this number is implementation-specific). Otherwise, ICE is considered in
+ // "weak connectivity".
+ //
+ // Note that the above notion of strong and weak connectivity is not defined
+ // in RFC 5245, and they apply to our current ICE implementation only.
+ //
+ // 1) iceCheckIntervalStrongConnectivityMs defines the interval applied to
+ // ALL candidate pairs when ICE is strongly connected,
+ // 2) iceCheckIntervalWeakConnectivityMs defines the counterpart for ALL
+ // pairs when ICE is weakly connected, and
+ // 3) iceCheckMinInterval defines the minimal interval (equivalently the
+ // maximum rate) that overrides the above two intervals when either of them
+ // is less.
+ public Integer iceCheckIntervalStrongConnectivityMs;
+ public Integer iceCheckIntervalWeakConnectivityMs;
public Integer iceCheckMinInterval;
// The interval in milliseconds at which STUN candidates will resend STUN binding requests
// to keep NAT bindings open.
@@ -437,6 +459,8 @@
iceCandidatePoolSize = 0;
pruneTurnPorts = false;
presumeWritableWhenFullyRelayed = false;
+ iceCheckIntervalStrongConnectivityMs = null;
+ iceCheckIntervalWeakConnectivityMs = null;
iceCheckMinInterval = null;
stunCandidateKeepaliveIntervalMs = null;
disableIPv6OnWifi = false;
@@ -530,6 +554,16 @@
}
@CalledByNative("RTCConfiguration")
+ Integer getIceCheckIntervalStrongConnectivity() {
+ return iceCheckIntervalStrongConnectivityMs;
+ }
+
+ @CalledByNative("RTCConfiguration")
+ Integer getIceCheckIntervalWeakConnectivity() {
+ return iceCheckIntervalWeakConnectivityMs;
+ }
+
+ @CalledByNative("RTCConfiguration")
Integer getIceCheckMinInterval() {
return iceCheckMinInterval;
}
diff --git a/sdk/android/src/jni/pc/peerconnection.cc b/sdk/android/src/jni/pc/peerconnection.cc
index 048d224..c18af7f 100644
--- a/sdk/android/src/jni/pc/peerconnection.cc
+++ b/sdk/android/src/jni/pc/peerconnection.cc
@@ -173,6 +173,16 @@
rtc_config->presume_writable_when_fully_relayed =
Java_RTCConfiguration_getPresumeWritableWhenFullyRelayed(jni,
j_rtc_config);
+ ScopedJavaLocalRef<jobject> j_ice_check_interval_strong_connectivity =
+ Java_RTCConfiguration_getIceCheckIntervalStrongConnectivity(jni,
+ j_rtc_config);
+ rtc_config->ice_check_interval_strong_connectivity =
+ JavaToNativeOptionalInt(jni, j_ice_check_interval_strong_connectivity);
+ ScopedJavaLocalRef<jobject> j_ice_check_interval_weak_connectivity =
+ Java_RTCConfiguration_getIceCheckIntervalWeakConnectivity(jni,
+ j_rtc_config);
+ rtc_config->ice_check_interval_weak_connectivity =
+ JavaToNativeOptionalInt(jni, j_ice_check_interval_weak_connectivity);
ScopedJavaLocalRef<jobject> j_ice_check_min_interval =
Java_RTCConfiguration_getIceCheckMinInterval(jni, j_rtc_config);
rtc_config->ice_check_min_interval =