准备查看WebRTC源码对应以下这些文章中的协议格式深入研究一下ICE。
这三篇文章是目前我看过的最好的ICE文章:
P2P通信标准协议(一)之STUN
P2P通信标准协议(二)之TURN
P2P通信标准协议(三)之ICE
这个可以做为补充:
P2P技术详解(三):P2P技术之STUN、TURN、ICE详解
先学习上面文章的基础知识,然后开始分析WebRTC创建PeerConnection直到连接Stun和Turn的流程:
bool PeerConnection::InitializePortAllocator_n(
...
if (ParseIceServers(configuration.servers, &stun_servers, &turn_servers) !=
...
port_allocator_->SetConfiguration(
stun_servers, turn_servers, configuration.ice_candidate_pool_size,
configuration.prune_turn_ports, configuration.turn_customizer,
configuration.stun_candidate_keepalive_interval);
...
}
bool PortAllocator::SetConfiguration(
...
stun_servers_ = stun_servers;
turn_servers_ = turn_servers;
...
// If |candidate_pool_size_| is greater than the number of pooled sessions,
// create new sessions.
while (static_cast<int>(pooled_sessions_.size()) < candidate_pool_size_) {
PortAllocatorSession* pooled_session = CreateSessionInternal("", 0, "", "");
pooled_session->StartGettingPorts();
pooled_sessions_.push_back(
std::unique_ptr<PortAllocatorSession>(pooled_session));
}
return true;
}
PeerConnection在初始化时创建了port_allocator_,同时调用了PortAllocator::SetConfiguration把stun_servers和turn_servers存储起来。
并且调用了BasicPortAllocatorSession::StartGettingPorts()
void BasicPortAllocatorSession::StartGettingPorts() {
...
network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START);
...
}
void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
switch (message->message_id) {
case MSG_CONFIG_START:
RTC_DCHECK(rtc::Thread::Current() == network_thread_);
GetPortConfigurations();
...
}
void BasicPortAllocatorSession::GetPortConfigurations() {
PortConfiguration* config = new PortConfiguration(allocator_->stun_servers(),
username(),
password());
for (const RelayServerConfig& turn_server : allocator_->turn_servers()) {
config->AddRelay(turn_server);
}
ConfigReady(config);
}
void BasicPortAllocatorSession::ConfigReady(PortConfiguration* config) {
network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_READY, config);
}
void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
switch (message->message_id) {
...
case MSG_CONFIG_READY:
RTC_DCHECK(rtc::Thread::Current() == network_thread_);
OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
break;
...
}
// Adds a configuration to the list.
void BasicPortAllocatorSession::OnConfigReady(PortConfiguration* config) {
if (config) {
configs_.push_back(config);
}
AllocatePorts();
}
…
// For each network, see if we have a sequence that covers it already. If not,
// create a new sequence to create the appropriate ports.
void BasicPortAllocatorSession::DoAllocate(bool disable_equivalent) {
...
AllocationSequence* sequence =
new AllocationSequence(this, networks[i], config, sequence_flags);
sequence->SignalPortAllocationComplete.connect(
this, &BasicPortAllocatorSession::OnPortAllocationComplete);
sequence->Init();
sequence->Start();
sequences_.push_back(sequence);
...
}
一路把PortConfiguration *config传进来,创建AllocationSequence* sequence,并且调用了Start()方法
void AllocationSequence::Start() {
state_ = kRunning;
session_->network_thread()->Post(RTC_FROM_HERE, this, MSG_ALLOCATION_PHASE);
// Take a snapshot of the best IP, so that when DisableEquivalentPhases is
// called next time, we enable all phases if the best IP has since changed.
previous_best_ip_ = network_->GetBestIP();
}
void AllocationSequence::OnMessage(rtc::Message* msg) {
RTC_DCHECK(rtc::Thread::Current() == session_->network_thread());
RTC_DCHECK(msg->message_id == MSG_ALLOCATION_PHASE);
const char* const PHASE_NAMES[kNumPhases] = {
"Udp", "Relay",