代码框图

image.png

SortConnectionsAndUpdateState

H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\p2p\base\p2p_transport_channel.cc
P2PTransportChannel::SortConnectionsAndUpdateState

image.png

  1. // Sort the available connections to find the best one. We also monitor
  2. // the number of available connections and the current state.
  3. void P2PTransportChannel::SortConnectionsAndUpdateState(
  4. IceControllerEvent reason_to_sort) {
  5. RTC_DCHECK_RUN_ON(network_thread_);
  6. // Make sure the connection states are up-to-date since this affects how they
  7. // will be sorted.
  8. UpdateConnectionStates();
  9. // Any changes after this point will require a re-sort.
  10. sort_dirty_ = false;
  11. // If necessary, switch to the new choice. Note that |top_connection| doesn't
  12. // have to be writable to become the selected connection although it will
  13. // have higher priority if it is writable.
  14. MaybeSwitchSelectedConnection(
  15. reason_to_sort, ice_controller_->SortAndSwitchConnection(reason_to_sort));
  16. // The controlled side can prune only if the selected connection has been
  17. // nominated because otherwise it may prune the connection that will be
  18. // selected by the controlling side.
  19. // TODO(honghaiz): This is not enough to prevent a connection from being
  20. // pruned too early because with aggressive nomination, the controlling side
  21. // will nominate every connection until it becomes writable.
  22. if (ice_role_ == ICEROLE_CONTROLLING ||
  23. (selected_connection_ && selected_connection_->nominated())) {
  24. PruneConnections();
  25. }
  26. // Check if all connections are timedout.
  27. bool all_connections_timedout = true;
  28. for (const Connection* conn : connections()) {
  29. if (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) {
  30. all_connections_timedout = false;
  31. break;
  32. }
  33. }
  34. // Now update the writable state of the channel with the information we have
  35. // so far.
  36. if (all_connections_timedout) {
  37. HandleAllTimedOut();
  38. }
  39. // Update the state of this channel.
  40. UpdateState();
  41. // Also possibly start pinging.
  42. // We could start pinging if:
  43. // * The first connection was created.
  44. // * ICE credentials were provided.
  45. // * A TCP connection became connected.
  46. MaybeStartPinging();
  47. }

BasicIceController::SortAndSwitchConnection

image.png
image.png

  1. IceControllerInterface::SwitchResult
  2. BasicIceController::SortAndSwitchConnection(IceControllerEvent reason) {
  3. // Find the best alternative connection by sorting. It is important to note
  4. // that amongst equal preference, writable connections, this will choose the
  5. // one whose estimated latency is lowest. So it is the only one that we
  6. // need to consider switching to.
  7. // TODO(honghaiz): Don't sort; Just use std::max_element in the right places.
  8. absl::c_stable_sort(
  9. connections_, [this](const Connection* a, const Connection* b) {
  10. int cmp = CompareConnections(a, b, absl::nullopt, nullptr);
  11. if (cmp != 0) {
  12. return cmp > 0;
  13. }
  14. // Otherwise, sort based on latency estimate.
  15. return a->rtt() < b->rtt();
  16. });
  17. RTC_LOG(LS_VERBOSE) << "Sorting " << connections_.size()
  18. << " available connections";
  19. for (size_t i = 0; i < connections_.size(); ++i) {
  20. RTC_LOG(LS_VERBOSE) << connections_[i]->ToString();
  21. }
  22. const Connection* top_connection =
  23. (!connections_.empty()) ? connections_[0] : nullptr;
  24. return ShouldSwitchConnection(reason, top_connection);
  25. }

依次比较,a b c d e , a和b比较,将结果b和c 比较,c和d比较。。。

BasicIceController::CompareConnections

image.png
remote_nomination提名

  1. int BasicIceController::CompareConnections(
  2. const Connection* a,
  3. const Connection* b,
  4. absl::optional<int64_t> receiving_unchanged_threshold,
  5. bool* missed_receiving_unchanged_threshold) const {
  6. RTC_CHECK(a != nullptr);
  7. RTC_CHECK(b != nullptr);
  8. // We prefer to switch to a writable and receiving connection over a
  9. // non-writable or non-receiving connection, even if the latter has
  10. // been nominated by the controlling side.
  11. int state_cmp = CompareConnectionStates(a, b, receiving_unchanged_threshold,
  12. missed_receiving_unchanged_threshold);
  13. if (state_cmp != 0) {
  14. return state_cmp;
  15. }
  16. if (ice_role_func_() == ICEROLE_CONTROLLED) {
  17. // Compare the connections based on the nomination states and the last data
  18. // received time if this is on the controlled side.
  19. if (a->remote_nomination() > b->remote_nomination()) {
  20. return a_is_better;
  21. }
  22. if (a->remote_nomination() < b->remote_nomination()) {
  23. return b_is_better;
  24. }
  25. if (a->last_data_received() > b->last_data_received()) {
  26. return a_is_better;
  27. }
  28. if (a->last_data_received() < b->last_data_received()) {
  29. return b_is_better;
  30. }
  31. }
  32. // Compare the network cost and priority.
  33. return CompareConnectionCandidates(a, b);
  34. }

BasicIceController::CompareConnectionStates

image.png

  1. // Compare two connections based on their writing, receiving, and connected
  2. // states.
  3. int BasicIceController::CompareConnectionStates(
  4. const Connection* a,
  5. const Connection* b,
  6. absl::optional<int64_t> receiving_unchanged_threshold,
  7. bool* missed_receiving_unchanged_threshold) const {
  8. // First, prefer a connection that's writable or presumed writable over
  9. // one that's not writable.
  10. bool a_writable = a->writable() || PresumedWritable(a);
  11. bool b_writable = b->writable() || PresumedWritable(b);
  12. if (a_writable && !b_writable) {
  13. return a_is_better;
  14. }
  15. if (!a_writable && b_writable) {
  16. return b_is_better;
  17. }
  18. // Sort based on write-state. Better states have lower values.
  19. if (a->write_state() < b->write_state()) {
  20. return a_is_better;
  21. }
  22. if (b->write_state() < a->write_state()) {
  23. return b_is_better;
  24. }
  25. // We prefer a receiving connection to a non-receiving, higher-priority
  26. // connection when sorting connections and choosing which connection to
  27. // switch to.
  28. if (a->receiving() && !b->receiving()) {
  29. return a_is_better;
  30. }
  31. if (!a->receiving() && b->receiving()) {
  32. if (!receiving_unchanged_threshold ||
  33. (a->receiving_unchanged_since() <= *receiving_unchanged_threshold &&
  34. b->receiving_unchanged_since() <= *receiving_unchanged_threshold)) {
  35. return b_is_better;
  36. }
  37. *missed_receiving_unchanged_threshold = true;
  38. }
  39. // WARNING: Some complexity here about TCP reconnecting.
  40. // When a TCP connection fails because of a TCP socket disconnecting, the
  41. // active side of the connection will attempt to reconnect for 5 seconds while
  42. // pretending to be writable (the connection is not set to the unwritable
  43. // state). On the passive side, the connection also remains writable even
  44. // though it is disconnected, and a new connection is created when the active
  45. // side connects. At that point, there are two TCP connections on the passive
  46. // side: 1. the old, disconnected one that is pretending to be writable, and
  47. // 2. the new, connected one that is maybe not yet writable. For purposes of
  48. // pruning, pinging, and selecting the selected connection, we want to treat
  49. // the new connection as "better" than the old one. We could add a method
  50. // called something like Connection::ImReallyBadEvenThoughImWritable, but that
  51. // is equivalent to the existing Connection::connected(), which we already
  52. // have. So, in code throughout this file, we'll check whether the connection
  53. // is connected() or not, and if it is not, treat it as "worse" than a
  54. // connected one, even though it's writable. In the code below, we're doing
  55. // so to make sure we treat a new writable connection as better than an old
  56. // disconnected connection.
  57. // In the case where we reconnect TCP connections, the original best
  58. // connection is disconnected without changing to WRITE_TIMEOUT. In this case,
  59. // the new connection, when it becomes writable, should have higher priority.
  60. if (a->write_state() == Connection::STATE_WRITABLE &&
  61. b->write_state() == Connection::STATE_WRITABLE) {
  62. if (a->connected() && !b->connected()) {
  63. return a_is_better;
  64. }
  65. if (!a->connected() && b->connected()) {
  66. return b_is_better;
  67. }
  68. }
  69. return 0;
  70. }

BasicIceController::CompareConnectionCandidates

image.png

  1. // Compares two connections based only on the candidate and network information.
  2. // Returns positive if |a| is better than |b|.
  3. int BasicIceController::CompareConnectionCandidates(const Connection* a,
  4. const Connection* b) const {
  5. int compare_a_b_by_networks =
  6. CompareCandidatePairNetworks(a, b, config_.network_preference);
  7. if (compare_a_b_by_networks != a_and_b_equal) {
  8. return compare_a_b_by_networks;
  9. }
  10. // Compare connection priority. Lower values get sorted last.
  11. if (a->priority() > b->priority()) {
  12. return a_is_better;
  13. }
  14. if (a->priority() < b->priority()) {
  15. return b_is_better;
  16. }
  17. // If we're still tied at this point, prefer a younger generation.
  18. // (Younger generation means a larger generation number).
  19. int cmp = (a->remote_candidate().generation() + a->generation()) -
  20. (b->remote_candidate().generation() + b->generation());
  21. if (cmp != 0) {
  22. return cmp;
  23. }
  24. // A periodic regather (triggered by the regather_all_networks_interval_range)
  25. // will produce candidates that appear the same but would use a new port. We
  26. // want to use the new candidates and purge the old candidates as they come
  27. // in, so use the fact that the old ports get pruned immediately to rank the
  28. // candidates with an active port/remote candidate higher.
  29. bool a_pruned = is_connection_pruned_func_(a);
  30. bool b_pruned = is_connection_pruned_func_(b);
  31. if (!a_pruned && b_pruned) {
  32. return a_is_better;
  33. }
  34. if (a_pruned && !b_pruned) {
  35. return b_is_better;
  36. }
  37. // Otherwise, must be equal
  38. return 0;
  39. }

BasicIceController::CompareCandidatePairNetworks

image.png

  1. int BasicIceController::CompareCandidatePairNetworks(
  2. const Connection* a,
  3. const Connection* b,
  4. absl::optional<rtc::AdapterType> network_preference) const {
  5. int compare_a_b_by_network_preference =
  6. CompareCandidatePairsByNetworkPreference(a, b,
  7. config_.network_preference);
  8. // The network preference has a higher precedence than the network cost.
  9. if (compare_a_b_by_network_preference != a_and_b_equal) {
  10. return compare_a_b_by_network_preference;
  11. }
  12. uint32_t a_cost = a->ComputeNetworkCost();
  13. uint32_t b_cost = b->ComputeNetworkCost();
  14. // Prefer lower network cost.
  15. if (a_cost < b_cost) {
  16. return a_is_better;
  17. }
  18. if (a_cost > b_cost) {
  19. return b_is_better;
  20. }
  21. return a_and_b_equal;
  22. }

CompareCandidatePairsByNetworkPreference

  1. int CompareCandidatePairsByNetworkPreference(
  2. const cricket::Connection* a,
  3. const cricket::Connection* b,
  4. absl::optional<rtc::AdapterType> network_preference) {
  5. bool a_uses_preferred_network =
  6. LocalCandidateUsesPreferredNetwork(a, network_preference);
  7. bool b_uses_preferred_network =
  8. LocalCandidateUsesPreferredNetwork(b, network_preference);
  9. if (a_uses_preferred_network && !b_uses_preferred_network) {
  10. return a_is_better;
  11. } else if (!a_uses_preferred_network && b_uses_preferred_network) {
  12. return b_is_better;
  13. }
  14. return a_and_b_equal;
  15. }