| 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);
|
| }
|
| }
|
|
|