1、ICEROLE_CONTROLLING ICEROLE_CONTROLLED等相关概念
ICE-CONTROLLED和ICE-CONTROLLING
在每次会话中,每个终端都有一个身份,有两种身份,即受控方(controlled role)和主控方(controlling role).
主控方负责选择最终用来通讯的候选地址对,受控方被告知哪个候选地址对用来进行哪次媒体流传输,
并且不生成更新过的offer来提示此次告知.发起ICE处理进程(即生成offer)的一方必须是主控方,而另一方则是受控方.
如果终端是受控方,那么在request中就必须加上ICE-CONTROLLED属性,同样,如果终端是主控方,就需要ICE-CONTROLLING属性.
2、具体的排序过程
通过调用peerconnection::AddIceCandidate,webrtc内部会一直调用至P2PTransportChannel::AddRemoteCandidate中,该方法源代码
void P2PTransportChannel::AddRemoteCandidate(const Candidate& candidate){
ASSERT(worker_thread_ == rtc::Thread::Current());
uint32_t generation = GetRemoteCandidateGeneration(candidate);
// If a remote candidate with a previous generation arrives, drop it.
if (generation < remote_ice_generation()) {
LOG(LS_WARNING) << "Dropping a remote candidate because its ufrag "
<< candidate.username()
<< " indicates it was for a previous generation.";
return;
}
Candidate new_remote_candidate(candidate);
new_remote_candidate.set_generation(generation);
if (remote_ice()) {
if (candidate.username().empty()) {
new_remote_candidate.set_username(remote_ice()->ufrag);
}
if (new_remote_candidate.username() == remote_ice()->ufrag) {
if (candidate.password().empty()) {
new_remote_candidate.set_password(remote_ice()->pwd);
}
} else {
LOG(LS_WARNING) << "A remote candidate arrives with an unknown ufrag: "
<< candidate.username();
}
}
//创建connections
CreateConnections(new_remote_candidate, NULL);
// 对所有conections进行排序
SortConnections();
}
下面是排序的具体过程
void P2PTransportChannel::SortConnections() {
ASSERT(worker_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;
//找出最优的连接
ConnectionCompare cmp;
std::stable_sort(connections_.begin(), connections_.end(), cmp);
LOG(LS_VERBOSE) << "Sorting " << connections_.size()
<< " available connections:";
..................
}
排序是通过<algorithm> 进行的,具体排序过程如下
class ConnectionCompare {
public:
bool operator()(const cricket::Connection *ca,
const cricket::Connection *cb) {
cricket::Connection* a = const_cast<cricket::Connection*>(ca);
cricket::Connection* b = const_cast<cricket::Connection*>(cb);
int cmp = CompareConnections(a, b);
if (cmp > 0)
return true;
if (cmp < 0)
return false;
// Otherwise, sort based on latency estimate.
return a->rtt() < b->rtt();
}
};
int CompareConnections(cricket::Connection* a, cricket::Connection* b) {
int state_cmp = CompareConnectionStates(a, b);
if (state_cmp != 0) {
return state_cmp;
}
// Compare the candidate information.
return CompareConnectionCandidates(a, b);
}
int CompareConnectionStates(cricket::Connection* a, cricket::Connection* b) {
// Sort based on write-state. Better states have lower values.
if (a->write_state() < b->write_state())
return 1;
if (a->write_state() > b->write_state())
return -1;
if (a->receiving() && !b->receiving())
return 1;
if (!a->receiving() && b->receiving())
return -1;
if (a->write_state() == cricket::Connection::STATE_WRITABLE &&
b->write_state() == cricket::Connection::STATE_WRITABLE) {
if (a->connected() && !b->connected()) {
return 1;
}
if (!a->connected() && b->connected()) {
return -1;
}
}
return 0;
}
int CompareConnectionCandidates(cricket::Connection* a,
cricket::Connection* b) {
uint32_t a_cost = a->ComputeNetworkCost();
uint32_t b_cost = b->ComputeNetworkCost();
// Smaller cost is better.
if (a_cost < b_cost) {
return 1;
}
if (a_cost > b_cost) {
return -1;
}
// Compare connection priority. Lower values get sorted last.
if (a->priority() > b->priority())
return 1;
if (a->priority() < b->priority())
return -1;
// If we're still tied at this point, prefer a younger generation.
return (a->remote_candidate().generation() + a->port()->generation()) -
(b->remote_candidate().generation() + b->port()->generation());
}
CompareConnections的流程概括为
- 比较连接状态
1.1 比较写状态
1.2 比较读状态
1.3 连接状态 - 比较连接的候选地址
2.1 比较cost
2.2 比较优先级
2.3 比较candidate的generation
对于连接成功的连接来说,因为cost在大部分情况下为0,所以一般比较得是candidate的priority,首先来看一个candidate的格式
candidate:499412426 2 udp 2122260222 192.168.0.136 54143 typ host generation 0 ufrag KQbng0ClMLl6gk2B network-id 3
499412426 //foundation
1 //component-id
udp //transport
2122260223 //priority
192.168.0.136 //connection-address
54135 //port
typ host //candidate-types
generation 0 //generation
ufrag KQbng0ClMLl6gk2B network-id 3
connection priority的计算过程
uint64_t Connection::priority() const {
uint64_t priority = 0;
// RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs
// Let G be the priority for the candidate provided by the controlling
// agent. Let D be the priority for the candidate provided by the
// controlled agent.
// pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
IceRole role = port_->GetIceRole();
if (role != ICEROLE_UNKNOWN) {
uint32_t g = 0;
uint32_t d = 0;
if (role == ICEROLE_CONTROLLING) {
g = local_candidate().priority();
d = remote_candidate_.priority();
} else {
g = remote_candidate_.priority();
d = local_candidate().priority();
}
priority = std::min(g, d);
priority = priority << 32;
priority += 2 * std::max(g, d) + (g > d ? 1 : 0);
}
return priority;
}
connection的rtt_(网络延时)的计算过程
//port.cc 787
//初始值
rtt_(DEFAULT_RTT), //DEFAULT_RTT = 3000
//port.cc 1222L
void Connection::OnConnectionRequestResponse(ConnectionRequest* request,
StunMessage* response) {
// Log at LS_INFO if we receive a ping response on an unwritable
// connection.
rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;
int rtt = request->Elapsed();
ReceivedPingResponse();
if (LOG_CHECK_LEVEL_V(sev)) {
bool use_candidate = (
response->GetByteString(STUN_ATTR_USE_CANDIDATE) != nullptr);
std::string pings;
PrintPingsSinceLastResponse(&pings, 5);
LOG_JV(sev, this) << "Received STUN ping response"
<< ", id=" << rtc::hex_encode(request->id())
<< ", code=0" // Makes logging easier to parse.
<< ", rtt=" << rtt
<< ", use_candidate=" << use_candidate
<< ", pings_since_last_response=" << pings;
}
rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
MaybeAddPrflxCandidate(request, response);
}
//Elapsed 相应跟请求的时间差
int StunRequest::Elapsed() const {
return static_cast<int>(rtc::Time64() - tstamp_);
}
网友评论