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 | |
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.
| |
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( | |
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.
| |
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 } | |
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
| |
225 if (best_connection == nullptr || !best_connection->nominated()) { | |
226 return true; | |
227 } | |
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.
| |
228 if (new_connection == last_nominated || | |
229 new_connection == last_data_received) { | |
230 return true; | |
231 } | |
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.
| |
232 // Compare the network cost and priority. | |
233 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.
| |
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 } |
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
| |
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 " |
756 << candidate.username() | 792 << candidate.username() |
(...skipping 680 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 } |
pthatcher1
2016/06/15 21:59:53
Can't this just be
if (connection == last_nominat
honghaiz3
2016/06/16 23:03:49
Ah Yes.
| |
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 |
1460 // changing from (writable, receiving) to (writable, not receiving). | 1505 // changing from (writable, receiving) to (writable, not receiving). |
1461 bool strongly_connected = !connection->weak(); | 1506 bool strongly_connected = !connection->weak(); |
1462 bool latest_generation = connection->local_candidate().generation() >= | 1507 bool latest_generation = connection->local_candidate().generation() >= |
1463 allocator_session()->generation(); | 1508 allocator_session()->generation(); |
1464 if (strongly_connected && latest_generation) { | 1509 if (strongly_connected && latest_generation) { |
(...skipping 17 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 } |
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.
| |
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); |
1504 RequestSort(); | 1549 RequestSort(); |
(...skipping 47 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; | |
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.
| |
1615 last_nominated_conn_ = nullptr; | |
1616 } else { | |
1617 last_data_received_conn_ = connection; | |
1565 } | 1618 } |
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.
| |
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) { |
1575 if (connection == best_connection_ && writable()) { | 1628 if (connection == best_connection_ && writable()) { |
(...skipping 112 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 |