如果之前没有选择connection,则就用排序好的第一个connection。否则,就要将当前使用的connection和排序后的第一个connection做比较,看哪个更佳就选哪个。
续上一节。

BasicIceController::SortAndSwitchConnection

image.png

BasicIceController::ShouldSwitchConnection

image.png
selectedconnection 之前前选中的connection
new_connection 排序后的选中connection

  1. IceControllerInterface::SwitchResult BasicIceController::ShouldSwitchConnection(
  2. IceControllerEvent reason,
  3. const Connection* new_connection) {
  4. if (!ReadyToSend(new_connection) || selected_connection_ == new_connection) {
  5. return {absl::nullopt, absl::nullopt};
  6. }
  7. if (selected_connection_ == nullptr) { // 第一次进来这里
  8. return HandleInitialSelectDampening(reason, new_connection);
  9. }
  10. // Do not switch to a connection that is not receiving if it is not on a
  11. // preferred network or it has higher cost because it may be just spuriously
  12. // better.
  13. int compare_a_b_by_networks = CompareCandidatePairNetworks(
  14. new_connection, selected_connection_, config_.network_preference);
  15. if (compare_a_b_by_networks == b_is_better && !new_connection->receiving()) {
  16. return {absl::nullopt, absl::nullopt};
  17. }
  18. bool missed_receiving_unchanged_threshold = false;
  19. absl::optional<int64_t> receiving_unchanged_threshold(
  20. rtc::TimeMillis() - config_.receiving_switching_delay_or_default());
  21. int cmp = CompareConnections(selected_connection_, new_connection,
  22. receiving_unchanged_threshold,
  23. &missed_receiving_unchanged_threshold);
  24. absl::optional<IceControllerEvent> recheck_event;
  25. if (missed_receiving_unchanged_threshold &&
  26. config_.receiving_switching_delay_or_default()) {
  27. // If we do not switch to the connection because it missed the receiving
  28. // threshold, the new connection is in a better receiving state than the
  29. // currently selected connection. So we need to re-check whether it needs
  30. // to be switched at a later time.
  31. recheck_event = reason;
  32. recheck_event->recheck_delay_ms =
  33. config_.receiving_switching_delay_or_default();
  34. }
  35. if (cmp < 0) {
  36. return {new_connection, absl::nullopt};
  37. } else if (cmp > 0) {
  38. return {absl::nullopt, recheck_event};
  39. }
  40. // If everything else is the same, switch only if rtt has improved by
  41. // a margin.
  42. if (new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement) {
  43. return {new_connection, absl::nullopt};
  44. }
  45. return {absl::nullopt, recheck_event};
  46. }

BasicIceController::HandleInitialSelectDampening

如果一开始没有选出connection,则进来这里。

image.png
跟踪代码,只执行截图里面的if语句。。

  1. IceControllerInterface::SwitchResult
  2. BasicIceController::HandleInitialSelectDampening(
  3. IceControllerEvent reason,
  4. const Connection* new_connection) {
  5. if (!field_trials_->initial_select_dampening.has_value() &&
  6. !field_trials_->initial_select_dampening_ping_received.has_value()) {
  7. // experiment not enabled => select connection.
  8. return {new_connection, absl::nullopt};
  9. }
  10. int64_t now = rtc::TimeMillis();
  11. int64_t max_delay = 0;
  12. if (new_connection->last_ping_received() > 0 &&
  13. field_trials_->initial_select_dampening_ping_received.has_value()) {
  14. max_delay = *field_trials_->initial_select_dampening_ping_received;
  15. } else if (field_trials_->initial_select_dampening.has_value()) {
  16. max_delay = *field_trials_->initial_select_dampening;
  17. }
  18. int64_t start_wait =
  19. initial_select_timestamp_ms_ == 0 ? now : initial_select_timestamp_ms_;
  20. int64_t max_wait_until = start_wait + max_delay;
  21. if (now >= max_wait_until) {
  22. RTC_LOG(LS_INFO) << "reset initial_select_timestamp_ = "
  23. << initial_select_timestamp_ms_
  24. << " selection delayed by: " << (now - start_wait) << "ms";
  25. initial_select_timestamp_ms_ = 0;
  26. return {new_connection, absl::nullopt};
  27. }
  28. // We are not yet ready to select first connection...
  29. if (initial_select_timestamp_ms_ == 0) {
  30. // Set timestamp on first time...
  31. // but run the delayed invokation everytime to
  32. // avoid possibility that we miss it.
  33. initial_select_timestamp_ms_ = now;
  34. RTC_LOG(LS_INFO) << "set initial_select_timestamp_ms_ = "
  35. << initial_select_timestamp_ms_;
  36. }
  37. int min_delay = max_delay;
  38. if (field_trials_->initial_select_dampening.has_value()) {
  39. min_delay = std::min(min_delay, *field_trials_->initial_select_dampening);
  40. }
  41. if (field_trials_->initial_select_dampening_ping_received.has_value()) {
  42. min_delay = std::min(
  43. min_delay, *field_trials_->initial_select_dampening_ping_received);
  44. }
  45. RTC_LOG(LS_INFO) << "delay initial selection up to " << min_delay << "ms";
  46. reason.type = IceControllerEvent::ICE_CONTROLLER_RECHECK;
  47. reason.recheck_delay_ms = min_delay;
  48. return {absl::nullopt, reason};
  49. }

P2PTransportChannel::OnNominated(Connection* conn)
-》
P2PTransportChannel::MaybeSwitchSelectedConnection

P2PTransportChannel::SortConnectionsAndUpdateState
-》
P2PTransportChannel::MaybeSwitchSelectedConnection

P2PTransportChannel::MaybeSwitchSelectedConnection

image.png

P2PTransportChannel::SwitchSelectedConnection

image.png
到这里就已经完成了选择connection。

  1. // Change the selected connection, and let listeners know.
  2. void P2PTransportChannel::SwitchSelectedConnection(Connection* conn,
  3. IceControllerEvent reason) {
  4. RTC_DCHECK_RUN_ON(network_thread_);
  5. // Note: if conn is NULL, the previous |selected_connection_| has been
  6. // destroyed, so don't use it.
  7. Connection* old_selected_connection = selected_connection_;
  8. selected_connection_ = conn;
  9. LogCandidatePairConfig(conn, webrtc::IceCandidatePairConfigType::kSelected);
  10. network_route_.reset();
  11. if (old_selected_connection) {
  12. old_selected_connection->set_selected(false);
  13. }
  14. if (selected_connection_) {
  15. ++nomination_;
  16. selected_connection_->set_selected(true);
  17. if (old_selected_connection) {
  18. RTC_LOG(LS_INFO) << ToString() << ": Previous selected connection: "
  19. << old_selected_connection->ToString();
  20. }
  21. RTC_LOG(LS_INFO) << ToString() << ": New selected connection: "
  22. << selected_connection_->ToString();
  23. SignalRouteChange(this, selected_connection_->remote_candidate());
  24. // This is a temporary, but safe fix to webrtc issue 5705.
  25. // TODO(honghaiz): Make all ENOTCONN error routed through the transport
  26. // channel so that it knows whether the media channel is allowed to
  27. // send; then it will only signal ready-to-send if the media channel
  28. // has been disallowed to send.
  29. if (selected_connection_->writable() ||
  30. PresumedWritable(selected_connection_)) {
  31. SignalReadyToSend(this);
  32. }
  33. network_route_.emplace(rtc::NetworkRoute());
  34. network_route_->connected = ReadyToSend(selected_connection_);
  35. network_route_->local = CreateRouteEndpointFromCandidate(
  36. /* local= */ true, selected_connection_->local_candidate(),
  37. /* uses_turn= */ selected_connection_->port()->Type() ==
  38. RELAY_PORT_TYPE);
  39. network_route_->remote = CreateRouteEndpointFromCandidate(
  40. /* local= */ false, selected_connection_->remote_candidate(),
  41. /* uses_turn= */ selected_connection_->remote_candidate().type() ==
  42. RELAY_PORT_TYPE);
  43. network_route_->last_sent_packet_id = last_sent_packet_id_;
  44. network_route_->packet_overhead =
  45. selected_connection_->local_candidate().address().ipaddr().overhead() +
  46. GetProtocolOverhead(selected_connection_->local_candidate().protocol());
  47. } else {
  48. RTC_LOG(LS_INFO) << ToString() << ": No selected connection";
  49. }
  50. if (conn != nullptr && ice_role_ == ICEROLE_CONTROLLING &&
  51. ((field_trials_.send_ping_on_switch_ice_controlling &&
  52. old_selected_connection != nullptr) ||
  53. field_trials_.send_ping_on_selected_ice_controlling)) {
  54. PingConnection(conn);
  55. MarkConnectionPinged(conn);
  56. }
  57. SignalNetworkRouteChanged(network_route_);
  58. // Create event for candidate pair change.
  59. if (selected_connection_) {
  60. CandidatePairChangeEvent pair_change;
  61. pair_change.reason = reason.ToString();
  62. pair_change.selected_candidate_pair = *GetSelectedCandidatePair();
  63. pair_change.last_data_received_ms =
  64. selected_connection_->last_data_received();
  65. if (old_selected_connection) {
  66. pair_change.estimated_disconnected_time_ms =
  67. ComputeEstimatedDisconnectedTimeMs(rtc::TimeMillis(),
  68. old_selected_connection);
  69. } else {
  70. pair_change.estimated_disconnected_time_ms = 0;
  71. }
  72. SignalCandidatePairChanged(pair_change);
  73. }
  74. ++selected_candidate_pair_changes_;
  75. ice_controller_->SetSelectedConnection(selected_connection_);
  76. }

可能切换连接的几种情况

image.png