OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 } | 193 } |
194 | 194 |
195 int prefs_cmp = CompareConnectionCandidates(a_conn, b_conn); | 195 int prefs_cmp = CompareConnectionCandidates(a_conn, b_conn); |
196 if (prefs_cmp != 0) { | 196 if (prefs_cmp != 0) { |
197 return prefs_cmp < 0; | 197 return prefs_cmp < 0; |
198 } | 198 } |
199 | 199 |
200 return b_conn->rtt() <= a_conn->rtt() + kMinImprovement; | 200 return b_conn->rtt() <= a_conn->rtt() + kMinImprovement; |
201 } | 201 } |
202 | 202 |
| 203 // Determines whether we should switch the best connection to |new_connection| |
| 204 // based the writable state, the last nominated connection, and the last |
| 205 // connection receiving data. This is to prevent that the controlled side may |
| 206 // switch the best connection too frequently when the controlling side is doing |
| 207 // aggressive nominations. With this implementation, the controlled side will |
| 208 // switch the best connection if the new nominated connection is writable, and |
| 209 // i) the best connection is nullptr, or |
| 210 // ii) the best connection was not nominated, or |
| 211 // iii) the new connection has been nominated twice consecutively, or |
| 212 // iv) the new connection is nominated and is receiving data, or |
| 213 // v) the new connection has lower cost or high priority. |
| 214 // TODO(honghaiz): Stop the aggressive nomination on the controlling side and |
| 215 // implement the ice-renomination option. |
| 216 bool ShouldSwitchOnNominatedOrDataReceived( |
| 217 cricket::Connection* best_connection, |
| 218 cricket::Connection* new_connection, |
| 219 cricket::Connection* last_nominated, |
| 220 cricket::Connection* last_data_received) { |
| 221 RTC_CHECK(new_connection != nullptr); |
| 222 if (!new_connection->writable()) { |
| 223 return false; |
| 224 } |
| 225 if (best_connection == nullptr || !best_connection->nominated()) { |
| 226 return true; |
| 227 } |
| 228 if (new_connection == last_nominated || |
| 229 new_connection == last_data_received) { |
| 230 return true; |
| 231 } |
| 232 // Compare the network cost and priority. |
| 233 return CompareConnectionCandidates(best_connection, new_connection) < 0; |
| 234 } |
| 235 |
203 } // unnamed namespace | 236 } // unnamed namespace |
204 | 237 |
205 namespace cricket { | 238 namespace cricket { |
206 | 239 |
207 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) | 240 // When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers) |
208 // for pinging. When the socket is writable, we will use only 1 Kbps because | 241 // for pinging. When the socket is writable, we will use only 1 Kbps because |
209 // we don't want to degrade the quality on a modem. These numbers should work | 242 // we don't want to degrade the quality on a modem. These numbers should work |
210 // well on a 28.8K modem, which is the slowest connection on which the voice | 243 // well on a 28.8K modem, which is the slowest connection on which the voice |
211 // quality is reasonable at all. | 244 // quality is reasonable at all. |
212 static const int PING_PACKET_SIZE = 60 * 8; | 245 static const int PING_PACKET_SIZE = 60 * 8; |
(...skipping 18 matching lines...) Expand all Loading... |
231 : P2PTransportChannel(transport_name, component, allocator) {} | 264 : P2PTransportChannel(transport_name, component, allocator) {} |
232 | 265 |
233 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, | 266 P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, |
234 int component, | 267 int component, |
235 PortAllocator* allocator) | 268 PortAllocator* allocator) |
236 : TransportChannelImpl(transport_name, component), | 269 : TransportChannelImpl(transport_name, component), |
237 allocator_(allocator), | 270 allocator_(allocator), |
238 worker_thread_(rtc::Thread::Current()), | 271 worker_thread_(rtc::Thread::Current()), |
239 incoming_only_(false), | 272 incoming_only_(false), |
240 error_(0), | 273 error_(0), |
241 best_connection_(NULL), | |
242 pending_best_connection_(NULL), | |
243 sort_dirty_(false), | 274 sort_dirty_(false), |
244 remote_ice_mode_(ICEMODE_FULL), | 275 remote_ice_mode_(ICEMODE_FULL), |
245 ice_role_(ICEROLE_UNKNOWN), | 276 ice_role_(ICEROLE_UNKNOWN), |
246 tiebreaker_(0), | 277 tiebreaker_(0), |
247 gathering_state_(kIceGatheringNew), | 278 gathering_state_(kIceGatheringNew), |
248 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), | 279 check_receiving_interval_(MIN_CHECK_RECEIVING_INTERVAL * 5), |
249 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, | 280 config_(MIN_CHECK_RECEIVING_INTERVAL * 50 /* receiving_timeout */, |
250 0 /* backup_connection_ping_interval */, | 281 0 /* backup_connection_ping_interval */, |
251 false /* gather_continually */, | 282 false /* gather_continually */, |
252 false /* prioritize_most_likely_candidate_pairs */, | 283 false /* prioritize_most_likely_candidate_pairs */, |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 return nullptr; | 753 return nullptr; |
723 } | 754 } |
724 *generation = params.rend() - it - 1; | 755 *generation = params.rend() - it - 1; |
725 return &(*it); | 756 return &(*it); |
726 } | 757 } |
727 | 758 |
728 void P2PTransportChannel::OnNominated(Connection* conn) { | 759 void P2PTransportChannel::OnNominated(Connection* conn) { |
729 ASSERT(worker_thread_ == rtc::Thread::Current()); | 760 ASSERT(worker_thread_ == rtc::Thread::Current()); |
730 ASSERT(ice_role_ == ICEROLE_CONTROLLED); | 761 ASSERT(ice_role_ == ICEROLE_CONTROLLED); |
731 | 762 |
732 if (conn->write_state() == Connection::STATE_WRITABLE) { | 763 if (best_connection_ == conn) { |
733 if (best_connection_ != conn) { | 764 return; |
734 pending_best_connection_ = NULL; | 765 } |
735 LOG(LS_INFO) << "Switching best connection on controlled side: " | 766 |
736 << conn->ToString(); | 767 if (ShouldSwitchOnNominatedOrDataReceived(best_connection_, conn, |
737 SwitchBestConnectionTo(conn); | 768 last_nominated_conn_, |
738 // Now we have selected the best connection, time to prune other existing | 769 last_data_received_conn_)) { |
739 // connections and update the read/write state of the channel. | 770 last_nominated_conn_ = nullptr; |
740 RequestSort(); | 771 last_data_received_conn_ = nullptr; |
741 } | 772 LOG(LS_INFO) << "Switching best connection on controlled side: " |
| 773 << conn->ToString(); |
| 774 SwitchBestConnectionTo(conn); |
| 775 // Now we have selected the best connection, time to prune other existing |
| 776 // connections and update the read/write state of the channel. |
| 777 RequestSort(); |
742 } else { | 778 } else { |
743 LOG(LS_INFO) << "Not switching the best connection on controlled side yet," | 779 LOG(LS_INFO) << "Not switching the best connection on controlled side yet: " |
744 << " because it's not writable: " << conn->ToString(); | 780 << conn->ToString(); |
745 pending_best_connection_ = conn; | 781 last_nominated_conn_ = conn; |
746 } | 782 } |
747 } | 783 } |
748 | 784 |
749 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { | 785 void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate) { |
750 ASSERT(worker_thread_ == rtc::Thread::Current()); | 786 ASSERT(worker_thread_ == rtc::Thread::Current()); |
751 | 787 |
752 uint32_t generation = GetRemoteCandidateGeneration(candidate); | 788 uint32_t generation = GetRemoteCandidateGeneration(candidate); |
753 // If a remote candidate with a previous generation arrives, drop it. | 789 // If a remote candidate with a previous generation arrives, drop it. |
754 if (generation < remote_ice_generation()) { | 790 if (generation < remote_ice_generation()) { |
755 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag " | 791 LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag " |
(...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1437 conn->Ping(last_ping_sent_ms_); | 1473 conn->Ping(last_ping_sent_ms_); |
1438 } | 1474 } |
1439 | 1475 |
1440 // When a connection's state changes, we need to figure out who to use as | 1476 // When a connection's state changes, we need to figure out who to use as |
1441 // the best connection again. It could have become usable, or become unusable. | 1477 // the best connection again. It could have become usable, or become unusable. |
1442 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { | 1478 void P2PTransportChannel::OnConnectionStateChange(Connection* connection) { |
1443 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1479 ASSERT(worker_thread_ == rtc::Thread::Current()); |
1444 | 1480 |
1445 // Update the best connection if the state change is from pending best | 1481 // Update the best connection if the state change is from pending best |
1446 // connection and role is controlled. | 1482 // connection and role is controlled. |
1447 if (ice_role_ == ICEROLE_CONTROLLED) { | 1483 if (ice_role_ == ICEROLE_CONTROLLED && connection == last_nominated_conn_) { |
1448 if (connection == pending_best_connection_ && connection->writable()) { | 1484 // This essentially requires that the connection is both last nominated |
1449 pending_best_connection_ = NULL; | 1485 // and receiving data, or the best connection is nullptr, in order |
| 1486 // to switch to |connection|. |
| 1487 if (connection == best_connection_) { |
| 1488 // If it is already the best connection, reset the last_nominated_conn_ |
| 1489 last_nominated_conn_ = nullptr; |
| 1490 } else if (ShouldSwitchOnNominatedOrDataReceived( |
| 1491 best_connection_, connection, nullptr, |
| 1492 last_data_received_conn_)) { |
| 1493 last_nominated_conn_ = nullptr; |
| 1494 last_data_received_conn_ = nullptr; |
1450 LOG(LS_INFO) << "Switching best connection on controlled side" | 1495 LOG(LS_INFO) << "Switching best connection on controlled side" |
1451 << " because it's now writable: " << connection->ToString(); | 1496 << " because it's now writable: " << connection->ToString(); |
1452 SwitchBestConnectionTo(connection); | 1497 SwitchBestConnectionTo(connection); |
1453 } | 1498 } |
1454 } | 1499 } |
1455 | 1500 |
1456 // May stop the allocator session when at least one connection becomes | 1501 // May stop the allocator session when at least one connection becomes |
1457 // strongly connected after starting to get ports and the local candidate of | 1502 // strongly connected after starting to get ports and the local candidate of |
1458 // the connection is at the latest generation. It is not enough to check | 1503 // the connection is at the latest generation. It is not enough to check |
1459 // that the connection becomes weakly connected because the connection may be | 1504 // that the connection becomes weakly connected because the connection may be |
(...skipping 22 matching lines...) Expand all Loading... |
1482 std::vector<Connection*>::iterator iter = | 1527 std::vector<Connection*>::iterator iter = |
1483 std::find(connections_.begin(), connections_.end(), connection); | 1528 std::find(connections_.begin(), connections_.end(), connection); |
1484 ASSERT(iter != connections_.end()); | 1529 ASSERT(iter != connections_.end()); |
1485 pinged_connections_.erase(*iter); | 1530 pinged_connections_.erase(*iter); |
1486 unpinged_connections_.erase(*iter); | 1531 unpinged_connections_.erase(*iter); |
1487 connections_.erase(iter); | 1532 connections_.erase(iter); |
1488 | 1533 |
1489 LOG_J(LS_INFO, this) << "Removed connection (" | 1534 LOG_J(LS_INFO, this) << "Removed connection (" |
1490 << static_cast<int>(connections_.size()) << " remaining)"; | 1535 << static_cast<int>(connections_.size()) << " remaining)"; |
1491 | 1536 |
1492 if (pending_best_connection_ == connection) { | 1537 if (last_nominated_conn_ == connection) { |
1493 pending_best_connection_ = NULL; | 1538 last_nominated_conn_ = nullptr; |
1494 } | 1539 } |
1495 | 1540 |
1496 // If this is currently the best connection, then we need to pick a new one. | 1541 // If this is currently the best connection, then we need to pick a new one. |
1497 // The call to SortConnections will pick a new one. It looks at the current | 1542 // The call to SortConnections will pick a new one. It looks at the current |
1498 // best connection in order to avoid switching between fairly similar ones. | 1543 // best connection in order to avoid switching between fairly similar ones. |
1499 // Since this connection is no longer an option, we can just set best to NULL | 1544 // Since this connection is no longer an option, we can just set best to NULL |
1500 // and re-choose a best assuming that there was no best connection. | 1545 // and re-choose a best assuming that there was no best connection. |
1501 if (best_connection_ == connection) { | 1546 if (best_connection_ == connection) { |
1502 LOG(LS_INFO) << "Best connection destroyed. Will choose a new one."; | 1547 LOG(LS_INFO) << "Best connection destroyed. Will choose a new one."; |
1503 SwitchBestConnectionTo(NULL); | 1548 SwitchBestConnectionTo(NULL); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1552 | 1597 |
1553 // Do not deliver, if packet doesn't belong to the correct transport channel. | 1598 // Do not deliver, if packet doesn't belong to the correct transport channel. |
1554 if (!FindConnection(connection)) | 1599 if (!FindConnection(connection)) |
1555 return; | 1600 return; |
1556 | 1601 |
1557 // Let the client know of an incoming packet | 1602 // Let the client know of an incoming packet |
1558 SignalReadPacket(this, data, len, packet_time, 0); | 1603 SignalReadPacket(this, data, len, packet_time, 0); |
1559 | 1604 |
1560 // May need to switch the sending connection based on the receiving media path | 1605 // May need to switch the sending connection based on the receiving media path |
1561 // if this is the controlled side. | 1606 // if this is the controlled side. |
1562 if (ice_role_ == ICEROLE_CONTROLLED && !best_nominated_connection() && | 1607 if (ice_role_ != ICEROLE_CONTROLLED || best_connection_ == connection) { |
1563 connection->writable() && best_connection_ != connection) { | 1608 return; |
| 1609 } |
| 1610 |
| 1611 if (ShouldSwitchOnNominatedOrDataReceived(best_connection_, connection, |
| 1612 last_nominated_conn_, nullptr)) { |
1564 SwitchBestConnectionTo(connection); | 1613 SwitchBestConnectionTo(connection); |
| 1614 last_data_received_conn_ = nullptr; |
| 1615 last_nominated_conn_ = nullptr; |
| 1616 } else { |
| 1617 last_data_received_conn_ = connection; |
1565 } | 1618 } |
1566 } | 1619 } |
1567 | 1620 |
1568 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { | 1621 void P2PTransportChannel::OnSentPacket(const rtc::SentPacket& sent_packet) { |
1569 ASSERT(worker_thread_ == rtc::Thread::Current()); | 1622 ASSERT(worker_thread_ == rtc::Thread::Current()); |
1570 | 1623 |
1571 SignalSentPacket(this, sent_packet); | 1624 SignalSentPacket(this, sent_packet); |
1572 } | 1625 } |
1573 | 1626 |
1574 void P2PTransportChannel::OnReadyToSend(Connection* connection) { | 1627 void P2PTransportChannel::OnReadyToSend(Connection* connection) { |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1688 | 1741 |
1689 // During the initial state when nothing has been pinged yet, return the first | 1742 // During the initial state when nothing has been pinged yet, return the first |
1690 // one in the ordered |connections_|. | 1743 // one in the ordered |connections_|. |
1691 return *(std::find_if(connections_.begin(), connections_.end(), | 1744 return *(std::find_if(connections_.begin(), connections_.end(), |
1692 [conn1, conn2](Connection* conn) { | 1745 [conn1, conn2](Connection* conn) { |
1693 return conn == conn1 || conn == conn2; | 1746 return conn == conn1 || conn == conn2; |
1694 })); | 1747 })); |
1695 } | 1748 } |
1696 | 1749 |
1697 } // namespace cricket | 1750 } // namespace cricket |
OLD | NEW |