WebRtc連接狀態變化

WebRtc連接狀態變化

  1. ICE收集完成的條件
  2. 連接狀態的變化


ComputeState:一旦ICE收集完成,至少應該存在一個可用的連接
1.如果had_connection_ 爲false,則狀態爲STATE_INIT
2.檢查所有的Connection,看是否有active的
3.該函數應該是在ICE收集完成時纔會調用
4.如果檢查所有Connection,沒有active的連接,則返回STATE_FAILED
// A channel is considered ICE completed once there is at most one active
// connection per network and at least one active connection.
IceTransportState P2PTransportChannel::ComputeState() const {
  if (!had_connection_) {
  return IceTransportState::STATE_INIT;
  }

  std::vector<Connection*> active_connections;
  for (Connection* connection : connections_) {
  if (connection->active()) {
  active_connections.push_back(connection);
  }
  }
  if (active_connections.empty()) {
  return IceTransportState::STATE_FAILED;
  }

  std::set<rtc::Network*> networks;
  for (Connection* connection : active_connections) {
  rtc::Network* network = connection->port()->Network();
  if (networks.find(network) == networks.end()) {
  networks.insert(network);
  } else {
  LOG_J(LS_VERBOSE, this) << "Ice not completed yet for this channel as "
  << network->ToString()
  << " has more than 1 connection.";
  return IceTransportState::STATE_CONNECTING;
  }
  }

  return IceTransportState::STATE_COMPLETED;
}





UpdateState :當一個連接被添加、刪除或者任何連接改變了write state時纔會被調用,以至於transport controller能夠得到最新的狀態。
然後,該函數不應該被調用太頻繁,以防出現多個狀態的改變,該函數應該在所有的狀態改變後纔會被調用。例如,我媽在SortConnectionsAndUpdate的最後調用。
1.首先得到當前的狀態,如果當前狀態和之前的狀態不一樣,則先判斷狀態轉變是否合理,即不能從某種狀態轉變成另外一種狀態
2.SingalStateChanged是產生狀態改變的信號???
3.set_writable設置寫的狀態?應該是判斷是否可以向對方發送數據???
4.set_receiving設置接受的狀態?應該是判斷是否可以接收對方的數據???

// Warning: UpdateState should eventually be called whenever a connection
// is added, deleted, or the write state of any connection changes so that the
// transport controller will get the up-to-date channel state. However it
// should not be called too often; in the case that multiple connection states
// change, it should be called after all the connection states have changed. For
// example, we call this at the end of SortConnectionsAndUpdateState.
void P2PTransportChannel::UpdateState() {
  IceTransportState state = ComputeState();
  if (state_ != state) {
  LOG_J(LS_INFO, this) << "Transport channel state changed from "
  << static_cast<int>(state_) << " to "
  << static_cast<int>(state);

  // Check that the requested transition is allowed. Note that
  // P2PTransportChannel does not (yet) implement a direct mapping of the ICE
  // states from the standard; the difference is covered by
  // TransportController and PeerConnection.
  switch (state_) {
  case IceTransportState::STATE_INIT:
  // TODO(deadbeef): Once we implement end-of-candidates signaling,
  // we shouldn't go from INIT to COMPLETED.
  RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
  state == IceTransportState::STATE_COMPLETED);
  break;
  case IceTransportState::STATE_CONNECTING:
  RTC_DCHECK(state == IceTransportState::STATE_COMPLETED ||
  state == IceTransportState::STATE_FAILED);
  break;
  case IceTransportState::STATE_COMPLETED:
  // TODO(deadbeef): Once we implement end-of-candidates signaling,
  // we shouldn't go from COMPLETED to CONNECTING.
  // Though we *can* go from COMPlETED to FAILED, if consent expires.
  RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
  state == IceTransportState::STATE_FAILED);
  break;
  case IceTransportState::STATE_FAILED:
  // TODO(deadbeef): Once we implement end-of-candidates signaling,
  // we shouldn't go from FAILED to CONNECTING or COMPLETED.
  RTC_DCHECK(state == IceTransportState::STATE_CONNECTING ||
  state == IceTransportState::STATE_COMPLETED);
  break;
  default:
  RTC_NOTREACHED();
  break;
  }
  state_ = state;
  SignalStateChanged(this);
  }

  // If our selected connection is "presumed writable" (TURN-TURN with no
  // CreatePermission required), act like we're already writable to the upper
  // layers, so they can start media quicker.
  bool writable =
  selected_connection_ && (selected_connection_->writable() ||
  PresumedWritable(selected_connection_));
  set_writable(writable);

  bool receiving = false;
  for (const Connection* connection : connections_) {
  if (connection->receiving()) {
  receiving = true;
  break;
  }
  }
  set_receiving(receiving);
}



SortConnectionsAndUpdateState:對可用的連接進行排序,找到最合適的連接。我們會監控這個可用連接數的變化以及當前的狀態。
1.

// Sort the available connections to find the best one. We also monitor
// the number of available connections and the current state.
void P2PTransportChannel::SortConnectionsAndUpdateState() {
  RTC_DCHECK(network_thread_ == rtc::Thread::Current());

  // Make sure the connection states are up-to-date since this affects how they
  // will be sorted.
  UpdateConnectionStates();

  // Any changes after this point will require a re-sort.
  sort_dirty_ = false;

  // Find the best alternative connection by sorting. It is important to note
  // that amongst equal preference, writable connections, this will choose the
  // one whose estimated latency is lowest. So it is the only one that we
  // need to consider switching to.
  // TODO(honghaiz): Don't sort; Just use std::max_element in the right places.
  std::stable_sort(connections_.begin(), connections_.end(),
  [this](const Connection* a, const Connection* b) {
  int cmp = CompareConnections(
  a, b, rtc::Optional<int64_t>(), nullptr);
  if (cmp != 0) {
  return cmp > 0;
  }
  // Otherwise, sort based on latency estimate.
  return a->rtt() < b->rtt();
  });

  LOG(LS_VERBOSE) << "Sorting " << connections_.size()
  << " available connections:";
  for (size_t i = 0; i < connections_.size(); ++i) {
  LOG(LS_VERBOSE) << connections_[i]->ToString();
  }

  Connection* top_connection =
  (connections_.size() > 0) ? connections_[0] : nullptr;

  // If necessary, switch to the new choice. Note that |top_connection| doesn't
  // have to be writable to become the selected connection although it will
  // have higher priority if it is writable.
  MaybeSwitchSelectedConnection(top_connection, "sorting");

  // The controlled side can prune only if the selected connection has been
  // nominated because otherwise it may prune the connection that will be
  // selected by the controlling side.
  // TODO(honghaiz): This is not enough to prevent a connection from being
  // pruned too early because with aggressive nomination, the controlling side
  // will nominate every connection until it becomes writable.
  if (ice_role_ == ICEROLE_CONTROLLING ||
  (selected_connection_ && selected_connection_->nominated())) {
  PruneConnections();
  }

  // Check if all connections are timedout.
  bool all_connections_timedout = true;
  for (size_t i = 0; i < connections_.size(); ++i) {
  if (connections_[i]->write_state() != Connection::STATE_WRITE_TIMEOUT) {
  all_connections_timedout = false;
  break;
  }
  }

  // Now update the writable state of the channel with the information we have
  // so far.
  if (all_connections_timedout) {
  HandleAllTimedOut();
  }

  // Update the state of this channel.
  UpdateState();

  // Also possibly start pinging.
  // We could start pinging if:
  // * The first connection was created.
  // * ICE credentials were provided.
  // * A TCP connection became connected.
  MaybeStartPinging();
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章