| Index: webrtc/p2p/base/p2ptransportchannel.cc | 
| diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc | 
| index f506126cef563f78eac4fb6a700e3c2053ffd4dc..56549d7408e13f5eaa9153aae915b2484918edf9 100644 | 
| --- a/webrtc/p2p/base/p2ptransportchannel.cc | 
| +++ b/webrtc/p2p/base/p2ptransportchannel.cc | 
| @@ -53,8 +53,8 @@ cricket::PortInterface::CandidateOrigin GetOrigin(cricket::PortInterface* port, | 
|  | 
| // Compares two connections based only on the candidate and network information. | 
| // Returns positive if |a| is better than |b|. | 
| -int CompareConnectionCandidates(cricket::Connection* a, | 
| -                                cricket::Connection* b) { | 
| +int CompareConnectionCandidates(const cricket::Connection* a, | 
| +                                const cricket::Connection* b) { | 
| uint32_t a_cost = a->ComputeNetworkCost(); | 
| uint32_t b_cost = b->ComputeNetworkCost(); | 
| // Smaller cost is better. | 
| @@ -78,7 +78,8 @@ int CompareConnectionCandidates(cricket::Connection* a, | 
|  | 
| // Compare two connections based on their writing, receiving, and connected | 
| // states. | 
| -int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) { | 
| +int CompareConnectionStates(const cricket::Connection* a, | 
| +                            const cricket::Connection* b) { | 
| // Sort based on write-state.  Better states have lower values. | 
| if (a->write_state() < b->write_state()) | 
| return 1; | 
| @@ -102,7 +103,7 @@ int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) { | 
| // side connects.  At that point, there are two TCP connections on the passive | 
| // side: 1. the old, disconnected one that is pretending to be writable, and | 
| // 2.  the new, connected one that is maybe not yet writable.  For purposes of | 
| -  // pruning, pinging, and selecting the best connection, we want to treat the | 
| +  // pruning, pinging, and selecting the connection to use, we want to treat the | 
| // new connection as "better" than the old one.  We could add a method called | 
| // something like Connection::ImReallyBadEvenThoughImWritable, but that is | 
| // equivalent to the existing Connection::connected(), which we already have. | 
| @@ -127,79 +128,6 @@ int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) { | 
| return 0; | 
| } | 
|  | 
| -int CompareConnections(cricket::Connection* a, cricket::Connection* b) { | 
| -  int state_cmp = CompareConnectionStates(a, b); | 
| -  if (state_cmp != 0) { | 
| -    return state_cmp; | 
| -  } | 
| -  // Compare the candidate information. | 
| -  return CompareConnectionCandidates(a, b); | 
| -} | 
| - | 
| -// Wraps the comparison connection into a less than operator that puts higher | 
| -// priority writable connections first. | 
| -class ConnectionCompare { | 
| - public: | 
| -  bool operator()(const cricket::Connection *ca, | 
| -                  const cricket::Connection *cb) { | 
| -    cricket::Connection* a = const_cast<cricket::Connection*>(ca); | 
| -    cricket::Connection* b = const_cast<cricket::Connection*>(cb); | 
| - | 
| -    // Compare first on writability and static preferences. | 
| -    int cmp = CompareConnections(a, b); | 
| -    if (cmp > 0) | 
| -      return true; | 
| -    if (cmp < 0) | 
| -      return false; | 
| - | 
| -    // Otherwise, sort based on latency estimate. | 
| -    return a->rtt() < b->rtt(); | 
| - | 
| -    // Should we bother checking for the last connection that last received | 
| -    // data? It would help rendezvous on the connection that is also receiving | 
| -    // packets. | 
| -    // | 
| -    // TODO: Yes we should definitely do this.  The TCP protocol gains | 
| -    // efficiency by being used bidirectionally, as opposed to two separate | 
| -    // unidirectional streams.  This test should probably occur before | 
| -    // comparison of local prefs (assuming combined prefs are the same).  We | 
| -    // need to be careful though, not to bounce back and forth with both sides | 
| -    // trying to rendevous with the other. | 
| -  } | 
| -}; | 
| - | 
| -// Determines whether we should switch between two connections, based first on | 
| -// connection states, static preferences, and then (if those are equal) on | 
| -// latency estimates. | 
| -bool ShouldSwitch(cricket::Connection* a_conn, | 
| -                  cricket::Connection* b_conn, | 
| -                  cricket::IceRole ice_role) { | 
| -  if (a_conn == b_conn) | 
| -    return false; | 
| - | 
| -  if (!a_conn || !b_conn)  // don't think the latter should happen | 
| -    return true; | 
| - | 
| -  // We prefer to switch to a writable and receiving connection over a | 
| -  // non-writable or non-receiving connection, even if the latter has | 
| -  // been nominated by the controlling side. | 
| -  int state_cmp = CompareConnectionStates(a_conn, b_conn); | 
| -  if (state_cmp != 0) { | 
| -    return state_cmp < 0; | 
| -  } | 
| -  if (ice_role == cricket::ICEROLE_CONTROLLED && a_conn->nominated()) { | 
| -    LOG(LS_VERBOSE) << "Controlled side did not switch due to nominated status"; | 
| -    return false; | 
| -  } | 
| - | 
| -  int prefs_cmp = CompareConnectionCandidates(a_conn, b_conn); | 
| -  if (prefs_cmp != 0) { | 
| -    return prefs_cmp < 0; | 
| -  } | 
| - | 
| -  return b_conn->rtt() <= a_conn->rtt() + kMinImprovement; | 
| -} | 
| - | 
| }  // unnamed namespace | 
|  | 
| namespace cricket { | 
| @@ -210,11 +138,11 @@ namespace cricket { | 
| // well on a 28.8K modem, which is the slowest connection on which the voice | 
| // quality is reasonable at all. | 
| static const int PING_PACKET_SIZE = 60 * 8; | 
| -// STRONG_PING_INTERVAL (480ms) is applied when the best connection is both | 
| +// STRONG_PING_INTERVAL (480ms) is applied when the selected connection is both | 
| // writable and receiving. | 
| static const int STRONG_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 1000; | 
| -// WEAK_PING_INTERVAL (48ms) is applied when the best connection is either not | 
| -// writable or not receiving. | 
| +// WEAK_PING_INTERVAL (48ms) is applied when the selected connection is either | 
| +// not writable or not receiving. | 
| const int WEAK_PING_INTERVAL = 1000 * PING_PACKET_SIZE / 10000; | 
|  | 
| // Writable connections are pinged at a faster rate while stabilizing. | 
| @@ -239,8 +167,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), | 
| @@ -303,6 +229,73 @@ void P2PTransportChannel::AddConnection(Connection* connection) { | 
| had_connection_ = true; | 
| } | 
|  | 
| +int P2PTransportChannel::CompareConnections( | 
| +    const cricket::Connection* a, | 
| +    const cricket::Connection* b) const { | 
| +  RTC_CHECK(a != nullptr); | 
| +  RTC_CHECK(b != nullptr); | 
| + | 
| +  // We prefer to switch to a writable and receiving connection over a | 
| +  // non-writable or non-receiving connection, even if the latter has | 
| +  // been nominated by the controlling side. | 
| +  int state_cmp = CompareConnectionStates(a, b); | 
| +  if (state_cmp != 0) { | 
| +    return state_cmp; | 
| +  } | 
| + | 
| +  if (ice_role_ == cricket::ICEROLE_CONTROLLED) { | 
| +    // Compare the connections based on the nomination states and the last data | 
| +    // received time if this is on the controlled side. | 
| +    if (a->nominated() != b->nominated()) { | 
| +      return b->nominated() ? -1 : 1; | 
| +    } | 
| + | 
| +    if (a->last_data_received() > b->last_data_received()) { | 
| +      return 1; | 
| +    } | 
| +    if (a->last_data_received() < b->last_data_received()) { | 
| +      return -1; | 
| +    } | 
| +  } | 
| + | 
| +  // Compare the network cost and priority. | 
| +  return CompareConnectionCandidates(a, b); | 
| +} | 
| + | 
| +// Determines whether we should switch the selected connection to | 
| +// |new_connection| based the writable/receiving state, the nomination state, | 
| +// and the last data received time. This prevents the controlled side from | 
| +// switching the selected connection too frequently when the controlling side | 
| +// is doing aggressive nominations. The precedence of the connection switching | 
| +// criteria is as follows: | 
| +// i) write/receiving/connected states | 
| +// ii) For controlled side, | 
| +//        a) nomination state, | 
| +//        b) last data received time. | 
| +// iii) Lower cost / higher priority. | 
| +// iv) rtt. | 
| +// TODO(honghaiz): Stop the aggressive nomination on the controlling side and | 
| +// implement the ice-renomination option. | 
| +bool P2PTransportChannel::ShouldSwitchSelectedConnection( | 
| +    cricket::Connection* new_connection) const { | 
| +  if (!new_connection || selected_connection_ == new_connection) { | 
| +    return false; | 
| +  } | 
| + | 
| +  if (selected_connection_ == nullptr) { | 
| +    return true; | 
| +  } | 
| + | 
| +  int cmp = CompareConnections(selected_connection_, new_connection); | 
| +  if (cmp != 0) { | 
| +    return cmp < 0; | 
| +  } | 
| + | 
| +  // If everything else is the same, switch only if rtt has improved by | 
| +  // a margin. | 
| +  return new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement; | 
| +} | 
| + | 
| void P2PTransportChannel::SetIceRole(IceRole ice_role) { | 
| ASSERT(worker_thread_ == rtc::Thread::Current()); | 
| if (ice_role_ != ice_role) { | 
| @@ -737,21 +730,24 @@ 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(); | 
| -    } | 
| -  } else { | 
| -    LOG(LS_INFO) << "Not switching the best connection on controlled side yet," | 
| -                 << " because it's not writable: " << conn->ToString(); | 
| -    pending_best_connection_ = conn; | 
| +  if (selected_connection_ == conn) { | 
| +    return; | 
| +  } | 
| + | 
| +  if (!ShouldSwitchSelectedConnection(conn)) { | 
| +    LOG(LS_INFO) | 
| +        << "Not switching the selected connection on controlled side yet: " | 
| +        << conn->ToString(); | 
| +    return; | 
| } | 
| + | 
| +  LOG(LS_INFO) | 
| +      << "Switching selected connection on controlled side due to nomination: " | 
| +      << conn->ToString(); | 
| +  SwitchSelectedConnection(conn); | 
| +  // Now that we have selected a connection, it is time to prune other | 
| +  // connections and update the read/write state of the channel. | 
| +  RequestSort(); | 
| } | 
|  | 
| void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { | 
| @@ -1001,7 +997,7 @@ bool P2PTransportChannel::GetOption(rtc::Socket::Option opt, int* value) { | 
| return true; | 
| } | 
|  | 
| -// Send data to the other side, using our best connection. | 
| +// Send data to the other side, using our selected connection. | 
| int P2PTransportChannel::SendPacket(const char *data, size_t len, | 
| const rtc::PacketOptions& options, | 
| int flags) { | 
| @@ -1010,16 +1006,16 @@ int P2PTransportChannel::SendPacket(const char *data, size_t len, | 
| error_ = EINVAL; | 
| return -1; | 
| } | 
| -  if (best_connection_ == NULL) { | 
| +  if (selected_connection_ == NULL) { | 
| error_ = EWOULDBLOCK; | 
| return -1; | 
| } | 
|  | 
| last_sent_packet_id_ = options.packet_id; | 
| -  int sent = best_connection_->Send(data, len, options); | 
| +  int sent = selected_connection_->Send(data, len, options); | 
| if (sent <= 0) { | 
| ASSERT(sent < 0); | 
| -    error_ = best_connection_->GetError(); | 
| +    error_ = selected_connection_->GetError(); | 
| } | 
| return sent; | 
| } | 
| @@ -1031,7 +1027,7 @@ bool P2PTransportChannel::GetStats(ConnectionInfos *infos) { | 
|  | 
| for (Connection* connection : connections_) { | 
| ConnectionInfo info = connection->stats(); | 
| -    info.best_connection = (best_connection_ == connection); | 
| +    info.best_connection = (selected_connection_ == connection); | 
| info.receiving = connection->receiving(); | 
| info.writable = (connection->write_state() == Connection::STATE_WRITABLE); | 
| info.timeout = | 
| @@ -1090,8 +1086,17 @@ void P2PTransportChannel::SortConnections() { | 
| // that amongst equal preference, writable connections, this will choose the | 
| // one whose estimated latency is lowest.  So it is the only one that we | 
| // need to consider switching to. | 
| -  ConnectionCompare cmp; | 
| -  std::stable_sort(connections_.begin(), connections_.end(), cmp); | 
| +  std::stable_sort( | 
| +      connections_.begin(), connections_.end(), | 
| +      [this](const cricket::Connection* a, const cricket::Connection* b) { | 
| +        int cmp = CompareConnections(a, b); | 
| +        if (cmp != 0) { | 
| +          return cmp > 0; | 
| +        } | 
| + | 
| +        // Otherwise, sort based on latency estimate. | 
| +        return a->rtt() < b->rtt(); | 
| +      }); | 
| LOG(LS_VERBOSE) << "Sorting " << connections_.size() | 
| << " available connections:"; | 
| for (size_t i = 0; i < connections_.size(); ++i) { | 
| @@ -1101,18 +1106,25 @@ void P2PTransportChannel::SortConnections() { | 
| Connection* top_connection = | 
| (connections_.size() > 0) ? connections_[0] : nullptr; | 
|  | 
| -  // If necessary, switch to the new choice. | 
| -  // Note that |top_connection| doesn't have to be writable to become the best | 
| -  // connection although it will have higher priority if it is writable. | 
| -  if (ShouldSwitch(best_connection_, top_connection, ice_role_)) { | 
| -    LOG(LS_INFO) << "Switching best connection: " << top_connection->ToString(); | 
| -    SwitchBestConnectionTo(top_connection); | 
| -  } | 
| - | 
| -  // Controlled side can prune only if the best connection has been nominated. | 
| -  // because otherwise it may delete the connection that will be selected by | 
| -  // the controlling side. | 
| -  if (ice_role_ == ICEROLE_CONTROLLING || best_nominated_connection()) { | 
| +  // If necessary, switch to the new choice. Note that |top_connection| doesn't | 
| +  // have to be writable to become the selected connection although it will | 
| +  // have higher priority if it is writable. | 
| +  if (ShouldSwitchSelectedConnection(top_connection)) { | 
| +    LOG(LS_INFO) << "Switching selected connection after sorting: " | 
| +                 << top_connection->ToString(); | 
| +    SwitchSelectedConnection(top_connection); | 
| +  } | 
| + | 
| +  // The controlled side can prune only if the selected connection has been | 
| +  // nominated because otherwise it may prune the connection that will be | 
| +  // selected by the controlling side. | 
| +  // TODO(honghaiz): This is not enough to prevent a connection from being | 
| +  // pruned too early because with aggressive nomination, the controlling side | 
| +  // will nominate every connection until it becomes writable. What we do now | 
| +  // is to un-prune a connection if a ping request comes with a nomination, or | 
| +  // new data is received on a nominated connection. | 
| +  if (ice_role_ == ICEROLE_CONTROLLING || | 
| +      (selected_connection_ && selected_connection_->nominated())) { | 
| PruneConnections(); | 
| } | 
|  | 
| @@ -1136,21 +1148,16 @@ void P2PTransportChannel::SortConnections() { | 
| UpdateState(); | 
| } | 
|  | 
| -Connection* P2PTransportChannel::best_nominated_connection() const { | 
| -  return (best_connection_ && best_connection_->nominated()) ? best_connection_ | 
| -                                                             : nullptr; | 
| -} | 
| - | 
| void P2PTransportChannel::PruneConnections() { | 
| // We can prune any connection for which there is a connected, writable | 
| // connection on the same network with better or equal priority.  We leave | 
| // those with better priority just in case they become writable later (at | 
| -  // which point, we would prune out the current best connection).  We leave | 
| +  // which point, we would prune out the current selected connection).  We leave | 
| // connections on other networks because they may not be using the same | 
| // resources and they may represent very distinct paths over which we can | 
| // switch. If the |premier| connection is not connected, we may be | 
| // reconnecting a TCP connection and temporarily do not prune connections in | 
| -  // this network. See the big comment in CompareConnections. | 
| +  // this network. See the big comment in CompareConnectionStates. | 
|  | 
| // Get a list of the networks that we are using. | 
| std::set<rtc::Network*> networks; | 
| @@ -1159,8 +1166,8 @@ void P2PTransportChannel::PruneConnections() { | 
| } | 
| for (rtc::Network* network : networks) { | 
| Connection* premier = GetBestConnectionOnNetwork(network); | 
| -    // Do not prune connections if the current best connection is weak on this | 
| -    // network. Otherwise, it may delete connections prematurely. | 
| +    // Do not prune connections if the current selected connection is weak on | 
| +    // this network. Otherwise, it may delete connections prematurely. | 
| if (!premier || premier->weak()) { | 
| continue; | 
| } | 
| @@ -1174,34 +1181,32 @@ void P2PTransportChannel::PruneConnections() { | 
| } | 
| } | 
|  | 
| -// Track the best connection, and let listeners know | 
| -void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) { | 
| -  // Note: if conn is NULL, the previous best_connection_ has been destroyed, | 
| -  // so don't use it. | 
| -  Connection* old_best_connection = best_connection_; | 
| -  best_connection_ = conn; | 
| -  if (best_connection_) { | 
| -    if (old_best_connection) { | 
| -      LOG_J(LS_INFO, this) << "Previous best connection: " | 
| -                           << old_best_connection->ToString(); | 
| +// Change the selected connection, and let listeners know. | 
| +void P2PTransportChannel::SwitchSelectedConnection(Connection* conn) { | 
| +  // Note: if conn is NULL, the previous |selected_connection_| has been | 
| +  // destroyed, so don't use it. | 
| +  Connection* old_selected_connection = selected_connection_; | 
| +  selected_connection_ = conn; | 
| +  if (selected_connection_) { | 
| +    if (old_selected_connection) { | 
| +      LOG_J(LS_INFO, this) << "Previous selected connection: " | 
| +                           << old_selected_connection->ToString(); | 
| } | 
| -    LOG_J(LS_INFO, this) << "New best connection: " | 
| -                         << best_connection_->ToString(); | 
| -    SignalRouteChange(this, best_connection_->remote_candidate()); | 
| +    LOG_J(LS_INFO, this) << "New selected connection: " | 
| +                         << selected_connection_->ToString(); | 
| +    SignalRouteChange(this, selected_connection_->remote_candidate()); | 
| // This is a temporary, but safe fix to webrtc issue 5705. | 
| // TODO(honghaiz): Make all EWOULDBLOCK error routed through the transport | 
| // channel so that it knows whether the media channel is allowed to | 
| // send; then it will only signal ready-to-send if the media channel | 
| // has been disallowed to send. | 
| -    if (best_connection_->writable()) { | 
| +    if (selected_connection_->writable()) { | 
| SignalReadyToSend(this); | 
| } | 
| } else { | 
| -    LOG_J(LS_INFO, this) << "No best connection"; | 
| +    LOG_J(LS_INFO, this) << "No selected connection"; | 
| } | 
| -  // TODO(honghaiz): rename best_connection_ with selected_connection_ or | 
| -  // selected_candidate pair_. | 
| -  SignalSelectedCandidatePairChanged(this, best_connection_, | 
| +  SignalSelectedCandidatePairChanged(this, selected_connection_, | 
| last_sent_packet_id_); | 
| } | 
|  | 
| @@ -1248,7 +1253,7 @@ void P2PTransportChannel::UpdateState() { | 
| SignalStateChanged(this); | 
| } | 
|  | 
| -  bool writable = best_connection_ && best_connection_->writable(); | 
| +  bool writable = selected_connection_ && selected_connection_->writable(); | 
| set_writable(writable); | 
|  | 
| bool receiving = false; | 
| @@ -1288,21 +1293,24 @@ void P2PTransportChannel::HandleAllTimedOut() { | 
| } | 
|  | 
| bool P2PTransportChannel::weak() const { | 
| -  return !best_connection_ || best_connection_->weak(); | 
| +  return !selected_connection_ || selected_connection_->weak(); | 
| } | 
|  | 
| -// If we have a best connection, return it, otherwise return top one in the | 
| +// If we have a selected connection, return it, otherwise return top one in the | 
| // list (later we will mark it best). | 
| Connection* P2PTransportChannel::GetBestConnectionOnNetwork( | 
| rtc::Network* network) const { | 
| -  // If the best connection is on this network, then it wins. | 
| -  if (best_connection_ && (best_connection_->port()->Network() == network)) | 
| -    return best_connection_; | 
| +  // If the selected connection is on this network, then it wins. | 
| +  if (selected_connection_ && | 
| +      (selected_connection_->port()->Network() == network)) { | 
| +    return selected_connection_; | 
| +  } | 
|  | 
| // Otherwise, we return the top-most in sorted order. | 
| for (size_t i = 0; i < connections_.size(); ++i) { | 
| -    if (connections_[i]->port()->Network() == network) | 
| +    if (connections_[i]->port()->Network() == network) { | 
| return connections_[i]; | 
| +    } | 
| } | 
|  | 
| return NULL; | 
| @@ -1334,8 +1342,9 @@ void P2PTransportChannel::OnCheckAndPing() { | 
| // Make sure the states of the connections are up-to-date (since this affects | 
| // which ones are pingable). | 
| UpdateConnectionStates(); | 
| -  // When the best connection is not receiving or not writable, or any active | 
| -  // connection has not been pinged enough times, use the weak ping interval. | 
| +  // When the selected connection is not receiving or not writable, or any | 
| +  // active connection has not been pinged enough times, use the weak ping | 
| +  // interval. | 
| bool need_more_pings_at_weak_interval = std::any_of( | 
| connections_.begin(), connections_.end(), [](Connection* conn) { | 
| return conn->active() && | 
| @@ -1356,9 +1365,9 @@ void P2PTransportChannel::OnCheckAndPing() { | 
| } | 
|  | 
| // A connection is considered a backup connection if the channel state | 
| -// is completed, the connection is not the best connection and it is active. | 
| +// is completed, the connection is not the selected connection and it is active. | 
| bool P2PTransportChannel::IsBackupConnection(Connection* conn) const { | 
| -  return state_ == STATE_COMPLETED && conn != best_connection_ && | 
| +  return state_ == STATE_COMPLETED && conn != selected_connection_ && | 
| conn->active(); | 
| } | 
|  | 
| @@ -1408,14 +1417,14 @@ bool P2PTransportChannel::IsPingable(Connection* conn, int64_t now) { | 
| return (now >= conn->last_ping_sent() + ping_interval); | 
| } | 
|  | 
| -bool P2PTransportChannel::IsBestConnectionPingable(int64_t now) { | 
| -  if (!best_connection_ || !best_connection_->connected() || | 
| -      !best_connection_->writable()) { | 
| +bool P2PTransportChannel::IsSelectedConnectionPingable(int64_t now) { | 
| +  if (!selected_connection_ || !selected_connection_->connected() || | 
| +      !selected_connection_->writable()) { | 
| return false; | 
| } | 
|  | 
| -  int interval = CalculateActiveWritablePingInterval(best_connection_, now); | 
| -  return best_connection_->last_ping_sent() + interval <= now; | 
| +  int interval = CalculateActiveWritablePingInterval(selected_connection_, now); | 
| +  return selected_connection_->last_ping_sent() + interval <= now; | 
| } | 
|  | 
| int P2PTransportChannel::CalculateActiveWritablePingInterval(Connection* conn, | 
| @@ -1436,15 +1445,15 @@ int P2PTransportChannel::CalculateActiveWritablePingInterval(Connection* conn, | 
| // Returns the next pingable connection to ping.  This will be the oldest | 
| // pingable connection unless we have a connected, writable connection that is | 
| // past the writable ping interval. When reconnecting a TCP | 
| -// connection, the best connection is disconnected, although still WRITABLE | 
| +// connection, the selected connection is disconnected, although still WRITABLE | 
| // while reconnecting. The newly created connection should be selected as the | 
| // ping target to become writable instead. See the big comment in | 
| -// CompareConnections. | 
| +// CompareConnectionStates. | 
| Connection* P2PTransportChannel::FindNextPingableConnection() { | 
| int64_t now = rtc::TimeMillis(); | 
| Connection* conn_to_ping = nullptr; | 
| -  if (IsBestConnectionPingable(now)) { | 
| -    conn_to_ping = best_connection_; | 
| +  if (IsSelectedConnectionPingable(now)) { | 
| +    conn_to_ping = selected_connection_; | 
| } else { | 
| conn_to_ping = FindConnectionToPing(now); | 
| } | 
| @@ -1462,21 +1471,22 @@ void P2PTransportChannel::MarkConnectionPinged(Connection* conn) { | 
| // explained below. | 
| // Set USE-CANDIDATE if doing ICE AND this channel is in CONTROLLING AND | 
| //    a) Channel is in FULL ICE AND | 
| -//      a.1) |conn| is the best connection OR | 
| -//      a.2) there is no best connection OR | 
| -//      a.3) the best connection is unwritable OR | 
| -//      a.4) |conn| has higher priority than best_connection. | 
| +//      a.1) |conn| is the selected connection OR | 
| +//      a.2) there is no selected connection OR | 
| +//      a.3) the selected connection is unwritable OR | 
| +//      a.4) |conn| has higher priority than selected_connection. | 
| //    b) we're doing LITE ICE AND | 
| -//      b.1) |conn| is the best_connection AND | 
| +//      b.1) |conn| is the selected_connection AND | 
| //      b.2) |conn| is writable. | 
| void P2PTransportChannel::PingConnection(Connection* conn) { | 
| bool use_candidate = false; | 
| if (remote_ice_mode_ == ICEMODE_FULL && ice_role_ == ICEROLE_CONTROLLING) { | 
| -    use_candidate = (conn == best_connection_) || (best_connection_ == NULL) || | 
| -                    (!best_connection_->writable()) || | 
| -                    (CompareConnectionCandidates(best_connection_, conn) < 0); | 
| -  } else if (remote_ice_mode_ == ICEMODE_LITE && conn == best_connection_) { | 
| -    use_candidate = best_connection_->writable(); | 
| +    use_candidate = | 
| +        (conn == selected_connection_) || (selected_connection_ == NULL) || | 
| +        (!selected_connection_->writable()) || | 
| +        (CompareConnectionCandidates(selected_connection_, conn) < 0); | 
| +  } else if (remote_ice_mode_ == ICEMODE_LITE && conn == selected_connection_) { | 
| +    use_candidate = selected_connection_->writable(); | 
| } | 
| conn->set_use_candidate_attr(use_candidate); | 
| last_ping_sent_ms_ = rtc::TimeMillis(); | 
| @@ -1484,21 +1494,11 @@ void P2PTransportChannel::PingConnection(Connection* conn) { | 
| } | 
|  | 
| // When a connection's state changes, we need to figure out who to use as | 
| -// the best connection again.  It could have become usable, or become unusable. | 
| +// the selected connection again.  It could have become usable, or become | 
| +// unusable. | 
| void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { | 
| ASSERT(worker_thread_ == rtc::Thread::Current()); | 
|  | 
| -  // 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; | 
| -      LOG(LS_INFO) << "Switching best connection on controlled side" | 
| -                   << " because it's now writable: " << connection->ToString(); | 
| -      SwitchBestConnectionTo(connection); | 
| -    } | 
| -  } | 
| - | 
| // May stop the allocator session when at least one connection becomes | 
| // strongly connected after starting to get ports and the local candidate of | 
| // the connection is at the latest generation. It is not enough to check | 
| @@ -1521,7 +1521,7 @@ void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { | 
| void P2PTransportChannel::OnConnectionDestroyed(Connection* connection) { | 
| ASSERT(worker_thread_ == rtc::Thread::Current()); | 
|  | 
| -  // Note: the previous best_connection_ may be destroyed by now, so don't | 
| +  // Note: the previous selected_connection_ may be destroyed by now, so don't | 
| // use it. | 
|  | 
| // Remove this connection from the list. | 
| @@ -1535,18 +1535,15 @@ 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 this is currently the best connection, then we need to pick a new one. | 
| -  // The call to SortConnections will pick a new one.  It looks at the current | 
| -  // best connection in order to avoid switching between fairly similar ones. | 
| -  // Since this connection is no longer an option, we can just set best to NULL | 
| -  // and re-choose a best assuming that there was no best connection. | 
| -  if (best_connection_ == connection) { | 
| -    LOG(LS_INFO) << "Best connection destroyed.  Will choose a new one."; | 
| -    SwitchBestConnectionTo(NULL); | 
| +  // If this is currently the selected connection, then we need to pick a new | 
| +  // one. The call to SortConnections will pick a new one.  It looks at the | 
| +  // current selected connection in order to avoid switching between fairly | 
| +  // similar ones. Since this connection is no longer an option, we can just | 
| +  // set selected to nullptr and re-choose a best assuming that there was no | 
| +  // selected connection. | 
| +  if (selected_connection_ == connection) { | 
| +    LOG(LS_INFO) << "selected connection destroyed.  Will choose a new one."; | 
| +    SwitchSelectedConnection(nullptr); | 
| RequestSort(); | 
| } | 
|  | 
| @@ -1606,9 +1603,11 @@ 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) { | 
| -    SwitchBestConnectionTo(connection); | 
| +  if (ice_role_ == ICEROLE_CONTROLLED && | 
| +      ShouldSwitchSelectedConnection(connection)) { | 
| +    LOG(LS_INFO) << "Switching selected connection on controlled side due to " | 
| +                 << "data received: " << connection->ToString(); | 
| +    SwitchSelectedConnection(connection); | 
| } | 
| } | 
|  | 
| @@ -1619,7 +1618,7 @@ void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { | 
| } | 
|  | 
| void P2PTransportChannel::OnReadyToSend(Connection* connection) { | 
| -  if (connection == best_connection_ && writable()) { | 
| +  if (connection == selected_connection_ && writable()) { | 
| SignalReadyToSend(this); | 
| } | 
| } | 
|  |