如果之前没有选择connection,则就用排序好的第一个connection。否则,就要将当前使用的connection和排序后的第一个connection做比较,看哪个更佳就选哪个。
续上一节。
BasicIceController::SortAndSwitchConnection
BasicIceController::ShouldSwitchConnection
selectedconnection 之前前选中的connection
new_connection 排序后的选中connection
IceControllerInterface::SwitchResult BasicIceController::ShouldSwitchConnection(
IceControllerEvent reason,
const Connection* new_connection) {
if (!ReadyToSend(new_connection) || selected_connection_ == new_connection) {
return {absl::nullopt, absl::nullopt};
}
if (selected_connection_ == nullptr) { // 第一次进来这里
return HandleInitialSelectDampening(reason, new_connection);
}
// Do not switch to a connection that is not receiving if it is not on a
// preferred network or it has higher cost because it may be just spuriously
// better.
int compare_a_b_by_networks = CompareCandidatePairNetworks(
new_connection, selected_connection_, config_.network_preference);
if (compare_a_b_by_networks == b_is_better && !new_connection->receiving()) {
return {absl::nullopt, absl::nullopt};
}
bool missed_receiving_unchanged_threshold = false;
absl::optional<int64_t> receiving_unchanged_threshold(
rtc::TimeMillis() - config_.receiving_switching_delay_or_default());
int cmp = CompareConnections(selected_connection_, new_connection,
receiving_unchanged_threshold,
&missed_receiving_unchanged_threshold);
absl::optional<IceControllerEvent> recheck_event;
if (missed_receiving_unchanged_threshold &&
config_.receiving_switching_delay_or_default()) {
// If we do not switch to the connection because it missed the receiving
// threshold, the new connection is in a better receiving state than the
// currently selected connection. So we need to re-check whether it needs
// to be switched at a later time.
recheck_event = reason;
recheck_event->recheck_delay_ms =
config_.receiving_switching_delay_or_default();
}
if (cmp < 0) {
return {new_connection, absl::nullopt};
} else if (cmp > 0) {
return {absl::nullopt, recheck_event};
}
// If everything else is the same, switch only if rtt has improved by
// a margin.
if (new_connection->rtt() <= selected_connection_->rtt() - kMinImprovement) {
return {new_connection, absl::nullopt};
}
return {absl::nullopt, recheck_event};
}
BasicIceController::HandleInitialSelectDampening
如果一开始没有选出connection,则进来这里。
跟踪代码,只执行截图里面的if语句。。
IceControllerInterface::SwitchResult
BasicIceController::HandleInitialSelectDampening(
IceControllerEvent reason,
const Connection* new_connection) {
if (!field_trials_->initial_select_dampening.has_value() &&
!field_trials_->initial_select_dampening_ping_received.has_value()) {
// experiment not enabled => select connection.
return {new_connection, absl::nullopt};
}
int64_t now = rtc::TimeMillis();
int64_t max_delay = 0;
if (new_connection->last_ping_received() > 0 &&
field_trials_->initial_select_dampening_ping_received.has_value()) {
max_delay = *field_trials_->initial_select_dampening_ping_received;
} else if (field_trials_->initial_select_dampening.has_value()) {
max_delay = *field_trials_->initial_select_dampening;
}
int64_t start_wait =
initial_select_timestamp_ms_ == 0 ? now : initial_select_timestamp_ms_;
int64_t max_wait_until = start_wait + max_delay;
if (now >= max_wait_until) {
RTC_LOG(LS_INFO) << "reset initial_select_timestamp_ = "
<< initial_select_timestamp_ms_
<< " selection delayed by: " << (now - start_wait) << "ms";
initial_select_timestamp_ms_ = 0;
return {new_connection, absl::nullopt};
}
// We are not yet ready to select first connection...
if (initial_select_timestamp_ms_ == 0) {
// Set timestamp on first time...
// but run the delayed invokation everytime to
// avoid possibility that we miss it.
initial_select_timestamp_ms_ = now;
RTC_LOG(LS_INFO) << "set initial_select_timestamp_ms_ = "
<< initial_select_timestamp_ms_;
}
int min_delay = max_delay;
if (field_trials_->initial_select_dampening.has_value()) {
min_delay = std::min(min_delay, *field_trials_->initial_select_dampening);
}
if (field_trials_->initial_select_dampening_ping_received.has_value()) {
min_delay = std::min(
min_delay, *field_trials_->initial_select_dampening_ping_received);
}
RTC_LOG(LS_INFO) << "delay initial selection up to " << min_delay << "ms";
reason.type = IceControllerEvent::ICE_CONTROLLER_RECHECK;
reason.recheck_delay_ms = min_delay;
return {absl::nullopt, reason};
}
P2PTransportChannel::OnNominated(Connection* conn)
-》
P2PTransportChannel::MaybeSwitchSelectedConnection
P2PTransportChannel::SortConnectionsAndUpdateState
-》
P2PTransportChannel::MaybeSwitchSelectedConnection
P2PTransportChannel::MaybeSwitchSelectedConnection
P2PTransportChannel::SwitchSelectedConnection
到这里就已经完成了选择connection。
// Change the selected connection, and let listeners know.
void P2PTransportChannel::SwitchSelectedConnection(Connection* conn,
IceControllerEvent reason) {
RTC_DCHECK_RUN_ON(network_thread_);
// 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;
LogCandidatePairConfig(conn, webrtc::IceCandidatePairConfigType::kSelected);
network_route_.reset();
if (old_selected_connection) {
old_selected_connection->set_selected(false);
}
if (selected_connection_) {
++nomination_;
selected_connection_->set_selected(true);
if (old_selected_connection) {
RTC_LOG(LS_INFO) << ToString() << ": Previous selected connection: "
<< old_selected_connection->ToString();
}
RTC_LOG(LS_INFO) << ToString() << ": 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 ENOTCONN 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 (selected_connection_->writable() ||
PresumedWritable(selected_connection_)) {
SignalReadyToSend(this);
}
network_route_.emplace(rtc::NetworkRoute());
network_route_->connected = ReadyToSend(selected_connection_);
network_route_->local = CreateRouteEndpointFromCandidate(
/* local= */ true, selected_connection_->local_candidate(),
/* uses_turn= */ selected_connection_->port()->Type() ==
RELAY_PORT_TYPE);
network_route_->remote = CreateRouteEndpointFromCandidate(
/* local= */ false, selected_connection_->remote_candidate(),
/* uses_turn= */ selected_connection_->remote_candidate().type() ==
RELAY_PORT_TYPE);
network_route_->last_sent_packet_id = last_sent_packet_id_;
network_route_->packet_overhead =
selected_connection_->local_candidate().address().ipaddr().overhead() +
GetProtocolOverhead(selected_connection_->local_candidate().protocol());
} else {
RTC_LOG(LS_INFO) << ToString() << ": No selected connection";
}
if (conn != nullptr && ice_role_ == ICEROLE_CONTROLLING &&
((field_trials_.send_ping_on_switch_ice_controlling &&
old_selected_connection != nullptr) ||
field_trials_.send_ping_on_selected_ice_controlling)) {
PingConnection(conn);
MarkConnectionPinged(conn);
}
SignalNetworkRouteChanged(network_route_);
// Create event for candidate pair change.
if (selected_connection_) {
CandidatePairChangeEvent pair_change;
pair_change.reason = reason.ToString();
pair_change.selected_candidate_pair = *GetSelectedCandidatePair();
pair_change.last_data_received_ms =
selected_connection_->last_data_received();
if (old_selected_connection) {
pair_change.estimated_disconnected_time_ms =
ComputeEstimatedDisconnectedTimeMs(rtc::TimeMillis(),
old_selected_connection);
} else {
pair_change.estimated_disconnected_time_ms = 0;
}
SignalCandidatePairChanged(pair_change);
}
++selected_candidate_pair_changes_;
ice_controller_->SetSelectedConnection(selected_connection_);
}