Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Unified Diff: webrtc/p2p/base/p2ptransportchannel.cc

Issue 2069493002: Do not switch best connection on the controlled side too frequently (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Add tests Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/p2p/base/p2ptransportchannel.cc
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
index d83726eab5a5b53c1af9edbda62f93907ac5e22c..9c27bf64681ffce9253a296266b32271fc06b265 100644
--- a/webrtc/p2p/base/p2ptransportchannel.cc
+++ b/webrtc/p2p/base/p2ptransportchannel.cc
@@ -200,6 +200,39 @@ bool ShouldSwitch(cricket::Connection* a_conn,
return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
}
+// Determines whether we should switch the best connection to |new_connection|
+// based the writable state, the last nominated connection, and the last
+// connection receiving data. This is to prevent that the controlled side may
+// switch the best connection too frequently when the controlling side is doing
+// aggressive nominations. With this implementation, the controlled side will
+// switch the best connection if the new nominated connection is writable, and
+// i) the best connection is nullptr, or
+// ii) the best connection was not nominated, or
+// iii) the new connection has been nominated twice consecutively, or
honghaiz3 2016/06/14 23:18:27 This would be useful for connections not receiving
pthatcher1 2016/06/15 21:59:53 As I mentioned in the another comment, I think tha
honghaiz3 2016/06/16 23:03:49 Done.
+// iv) the new connection is nominated and is receiving data, or
+// v) the new connection has lower cost or high priority.
+// TODO(honghaiz): Stop the aggressive nomination on the controlling side and
+// implement the ice-renomination option.
+bool ShouldSwitchOnNominatedOrDataReceived(
pthatcher1 2016/06/15 21:59:53 I think this should be called ShouldSwitchSelected
honghaiz3 2016/06/16 23:03:48 I don't think it should use the current ShouldSwit
pthatcher1 2016/06/17 00:27:11 That will only happen if the controlling side isn'
honghaiz3 2016/06/17 19:18:18 Done.
+ cricket::Connection* best_connection,
+ cricket::Connection* new_connection,
+ cricket::Connection* last_nominated,
+ cricket::Connection* last_data_received) {
+ RTC_CHECK(new_connection != nullptr);
+ if (!new_connection->writable()) {
+ return false;
+ }
pthatcher1 2016/06/15 21:59:53 Shouldn't this use the "comparison of writable sta
honghaiz3 2016/06/16 01:13:08 Right. The new connection is already writable. Pl
honghaiz3 2016/06/16 23:03:49 If a nominated connection is not writable, it won'
pthatcher1 2016/06/17 00:27:11 True. "if (!wrtible()) { return false; }" is more
honghaiz3 2016/06/17 19:18:17 Changed this logic to just compare the write/recei
+ if (best_connection == nullptr || !best_connection->nominated()) {
+ return true;
+ }
pthatcher1 2016/06/15 21:59:53 But the new_connection might not be nominated eith
honghaiz3 2016/06/16 23:03:49 This method is primarily called when it is nominat
pthatcher1 2016/06/17 00:27:11 If the controlling side isn't aggressive and none
honghaiz3 2016/06/17 19:18:17 Done.
+ if (new_connection == last_nominated ||
+ new_connection == last_data_received) {
+ return true;
+ }
pthatcher1 2016/06/15 21:59:53 Perhaps instead of recording the last conn that re
honghaiz3 2016/06/16 23:03:48 using the timestamp is less effective as that only
pthatcher1 2016/06/17 00:27:11 I mean something like this: if (connection->last_
honghaiz3 2016/06/17 19:18:17 Done.
+ // Compare the network cost and priority.
+ return CompareConnectionCandidates(best_connection, new_connection) < 0;
pthatcher1 2016/06/15 21:59:53 I think we should make all the logic very similar
honghaiz3 2016/06/16 01:13:08 As I mentioned in another comment, if the current
pthatcher1 2016/06/17 00:27:11 I'm mostly suggesting we make the logic clear. Sw
honghaiz3 2016/06/17 19:18:17 Done.
+}
+
} // unnamed namespace
namespace cricket {
@@ -238,8 +271,6 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
worker_thread_(rtc::Thread::Current()),
incoming_only_(false),
error_(0),
- best_connection_(NULL),
- pending_best_connection_(NULL),
sort_dirty_(false),
remote_ice_mode_(ICEMODE_FULL),
ice_role_(ICEROLE_UNKNOWN),
@@ -729,20 +760,25 @@ void P2PTransportChannel::OnNominated(Connection* conn) {
ASSERT(worker_thread_ == rtc::Thread::Current());
ASSERT(ice_role_ == ICEROLE_CONTROLLED);
- if (conn->write_state() == Connection::STATE_WRITABLE) {
- if (best_connection_ != conn) {
- pending_best_connection_ = NULL;
- LOG(LS_INFO) << "Switching best connection on controlled side: "
- << conn->ToString();
- SwitchBestConnectionTo(conn);
- // Now we have selected the best connection, time to prune other existing
- // connections and update the read/write state of the channel.
- RequestSort();
- }
+ if (best_connection_ == conn) {
+ return;
+ }
+
+ if (ShouldSwitchOnNominatedOrDataReceived(best_connection_, conn,
+ last_nominated_conn_,
+ last_data_received_conn_)) {
+ last_nominated_conn_ = nullptr;
+ last_data_received_conn_ = nullptr;
+ LOG(LS_INFO) << "Switching best connection on controlled side: "
+ << conn->ToString();
+ SwitchBestConnectionTo(conn);
+ // Now we have selected the best connection, time to prune other existing
+ // connections and update the read/write state of the channel.
+ RequestSort();
} else {
- LOG(LS_INFO) << "Not switching the best connection on controlled side yet,"
- << " because it's not writable: " << conn->ToString();
- pending_best_connection_ = conn;
+ LOG(LS_INFO) << "Not switching the best connection on controlled side yet: "
+ << conn->ToString();
+ last_nominated_conn_ = conn;
}
pthatcher1 2016/06/15 21:59:53 Can this just be this? if (!ShouldSwitchSelectedC
honghaiz3 2016/06/16 23:03:49 Done. Regarding the logging, I think the benefit
pthatcher1 2016/06/17 00:27:11 What about RequestSort()? Shouldn't we do that in
}
@@ -1444,9 +1480,18 @@ void P2PTransportChannel::OnConnectionStateChange(Connection* connection) {
// Update the best connection if the state change is from pending best
// connection and role is controlled.
- if (ice_role_ == ICEROLE_CONTROLLED) {
- if (connection == pending_best_connection_ && connection->writable()) {
- pending_best_connection_ = NULL;
+ if (ice_role_ == ICEROLE_CONTROLLED && connection == last_nominated_conn_) {
+ // This essentially requires that the connection is both last nominated
+ // and receiving data, or the best connection is nullptr, in order
+ // to switch to |connection|.
+ if (connection == best_connection_) {
+ // If it is already the best connection, reset the last_nominated_conn_
+ last_nominated_conn_ = nullptr;
+ } else if (ShouldSwitchOnNominatedOrDataReceived(
+ best_connection_, connection, nullptr,
+ last_data_received_conn_)) {
+ last_nominated_conn_ = nullptr;
+ last_data_received_conn_ = nullptr;
LOG(LS_INFO) << "Switching best connection on controlled side"
<< " because it's now writable: " << connection->ToString();
SwitchBestConnectionTo(connection);
@@ -1489,8 +1534,8 @@ void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) {
LOG_J(LS_INFO, this) << "Removed connection ("
<< static_cast<int>(connections_.size()) << " remaining)";
- if (pending_best_connection_ == connection) {
- pending_best_connection_ = NULL;
+ if (last_nominated_conn_ == connection) {
+ last_nominated_conn_ = nullptr;
}
pthatcher1 2016/06/15 21:59:53 I think we should just remove these lines and have
honghaiz3 2016/06/16 23:03:49 Done.
// If this is currently the best connection, then we need to pick a new one.
@@ -1559,9 +1604,17 @@ void P2PTransportChannel::OnReadPacket(Connection* connection,
// May need to switch the sending connection based on the receiving media path
// if this is the controlled side.
- if (ice_role_ == ICEROLE_CONTROLLED && !best_nominated_connection() &&
- connection->writable() && best_connection_ != connection) {
+ if (ice_role_ != ICEROLE_CONTROLLED || best_connection_ == connection) {
+ return;
+ }
+
+ if (ShouldSwitchOnNominatedOrDataReceived(best_connection_, connection,
+ last_nominated_conn_, nullptr)) {
SwitchBestConnectionTo(connection);
+ last_data_received_conn_ = nullptr;
pthatcher1 2016/06/15 21:59:53 Why would we set this to nullptr?
honghaiz3 2016/06/16 23:03:48 Perhaps not necessary. Removed.
+ last_nominated_conn_ = nullptr;
+ } else {
+ last_data_received_conn_ = connection;
}
pthatcher1 2016/06/15 21:59:53 Wouldn't it make more sense to do this? last_data
honghaiz3 2016/06/16 23:03:49 Done.
}

Powered by Google App Engine
This is Rietveld 408576698