每个终端都有一系列传输地址(包括传输协议、IP地址和端口)的候选,可以用来和其他端点进行通信。其中可能包括:
1、直接和网络接口联系的传输地址(host address)
2、经过NAT转换的传输地址,即反射地址(server reflective address)
3、TURN服务器分配的中继地址(relay address)
虽然潜在要求任意一个主叫Client的候选地址都能用来和被叫Client的候选地址进行通信。但是实际中发现有许多组合是无法工作的。举例来说,如果主叫Client和被叫Client都在NAT之后而且不处于同一内网,他们的直接地址就无法进行通信。ICE的目的就是为了发现哪一对候选地址的组合可以工作,并且通过系统的方法对所有组合进行测试(用一种精心挑选的顺序)。
在rfc5245定义里面,实现ICE一共有六个步骤:收集候选地址、连通性测试、候选排序、冻结候选、检查的安全性、ICE结束。webrtc结合实际应用,优化这六步为如下五步:收集候选地址、在信令通道中交换候选选项、执行连接检查、选定并启动媒体。
1、实现收集候选地址核心函数:BasicPortAllocatorSession::DoAllocate
2、在信令通道中交换候选选项:发送本端的候选选项核心函数:AllocationSequence::EnableProtocol
接收远端的候选选项核心函数:PeerConnection::AddIceCandidate
3、执行连接检查核心函数: P2PTransportChannel::SortConnectionsAndUpdateState
4、选定并启动媒体核心函数:P2PTransportChannel::OnReadyToSend
过程中检测有变化时:P2PTransportChannel::SwitchSelectedConnection
一、收集候选地址
1、获取turn、stun服务器信息处理流程
Conductor::InitializePeerConnection
->Conductor::CreatePeerConnection->PeerConnectionFactory::CreatePeerConnection
->PeerConnection::Initialize
->PeerConnection::InitializePortAllocator_n//这个函数解析配置信息,确定探测类型及参数。
->PortAllocator::SetConfiguration//这里配置服务器信息。
2、生效turn、stun服务器处理流程
WebRtcSessionDescriptionFactory::OnMessage
->Conductor::OnSuccess
->PeerConnection::SetLocalDescription (session_->MaybeStartGathering())
->WebRtcSession::MaybeStartGathering
->TransportController::MaybeStartGathering
->TransportController::MaybeStartGathering_n
->P2PTransportChannel::MaybeStartGathering
AddAllocatorSession(allocator_->CreateSession());//注册信号量
allocator_sessions_.back()->StartGettingPorts(); //启动Port资源申请消息
当P2PTransportChannel::MaybeStartGathering函数调用BasicPortAllocatorSession::StartGettingPorts后,就会启动MSG_CONFIG_START消息处理流程。开始收集本端的candidates信息。
3、Port资源申请状态机
enum {
MSG_CONFIG_START,
MSG_CONFIG_READY,
MSG_ALLOCATE,
MSG_ALLOCATION_PHASE,
MSG_SEQUENCEOBJECTS_CREATED,
MSG_CONFIG_STOP,
};
4、Port状态机接口函数
void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
switch (message->message_id) {
case MSG_CONFIG_START:
GetPortConfigurations();
break;
case MSG_CONFIG_READY:
OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
break;
case MSG_ALLOCATE:
OnAllocate();
break;
case MSG_SEQUENCEOBJECTS_CREATED:
OnAllocationSequenceObjectsCreated();
break;
case MSG_CONFIG_STOP:
OnConfigStop();
break;
default:
RTC_NOTREACHED();
}
}
1、MSG_CONFIG_START:申请stun配置文件信息,在配置文件中增加turn信息。配置OK后 ,向消息队列发送ready消息。
2、MSG_CONFIG_READY:push在START里面创建的配置信息到configs_,向消息队列发送MSG_ALLOCATE消息。
3、MSG_ALLOCATE:在这里会创建Port资源,收集candidates信息。
AllocationSequence* sequence =new AllocationSequence();//申请AllocationSequence类
sequence->SignalPortAllocationComplete.connect();//注册信号量
sequence->Init();//启动给自己发送MSG_ALLOCATION_PHASE消息队列
sequence->Start();
sequences_.push_back(sequence);
4、MSG_ALLOCATION_PHASE:Port申请处理流程
void AllocationSequence::OnMessage(rtc::Message* msg) {
RTC_DCHECK(msg->message_id == MSG_ALLOCATION_PHASE);
// Perform all of the phases in the current step.
switch (phase_) {
case PHASE_UDP:
CreateUDPPorts();//申请udp port资源
CreateStunPorts();//申请 stun port资源
EnableProtocol(PROTO_UDP);
break;
case PHASE_RELAY:
CreateRelayPorts();//申请GTURN或TURN port资源
break;
case PHASE_TCP:
CreateTCPPorts();//申请TCP Port资源
EnableProtocol(PROTO_TCP);
break;
case PHASE_SSLTCP:
state_ = kCompleted;//不需要继续探测,停止给自己发MSG_ALLOCATION_PHASE消息
EnableProtocol(PROTO_SSLTCP);
break;
}
if (state() == kRunning) {
++phase_;//更新探测阶段
session_->network_thread()->PostDelayed(RTC_FROM_HERE,MSG_ALLOCATION_PHASE);//给自己发消息。
} else {
session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);//清除给自己发消息资源
SignalPortAllocationComplete(this);//发送信号量,知会需要探测的Port资源都已经申请完毕。
}
}
5、发送candidates信息给对端:每次调用EnableProtocol函数,就是将本地的Candidates信息,发送给对端的Client
AllocationSequence::EnableProtocol
->BasicPortAllocatorSession::OnProtocolEnabled
->SignalCandidatesReady
->P2PTransportChannel::OnCandidatesReady
->SignalCandidateGathered
->TransportController::OnChannelCandidateGathered_n
->SignalCandidatesGathered
->WebRtcSession::OnTransportControllerCandidatesGathered
->Conductor::OnIceCandidate
->Conductor::SendMessage
->PeerConnectionClient::SendToPeer
Port资源申请结束后,通过信号量传递该信息:
SignalPortAllocationComplete信号量触发调用
BasicPortAllocatorSession::OnPortAllocationComplete
二、接收对端候选选项
当主叫Client获得了它全部的候选地址,把它们按优先级从高到低排序后通过信令通道(SDP offer)发送给被叫Client。被叫Client收到后做同样的事,然后通过响应发给主叫Client。最后,每个agent都拥有了自己和对方的候选地址。它们共同组成CANDIDATE PAIRS(候选地址对)。client通过CANDIDATE PAIRS发送给对端STUN request来检查它们。
1、处理HTTP的POST/message里面的SDP信令
Conductor::OnMessageFromPeer
->PeerConnection::SetRemoteDescription
->WebRtcSession::SetRemoteDescription
->WebRtcSession::UpdateSessionState
->WebRtcSession::PushdownTransportDescription
->WebRtcSession::PushdownRemoteTransportDescription
->TransportController::SetRemoteTransportDescription
->TransportController::SetRemoteTransportDescription_n
->JsepTransport::SetRemoteTransportDescription
->JsepTransport::ApplyRemoteTransportDescription
->P2PTransportChannel::SetRemoteIceParameters
->P2PTransportChannel::RequestSortAndStateUpdate
->P2PTransportChannel::SortConnectionsAndUpdateState
2、处理HTTP的POST/message里面的Candidate信令
Conductor::OnMessageFromPeer
->PeerConnection::AddIceCandidate->WebRtcSession::ProcessIceMessage
->WebRtcSession::UseCandidate
->TransportController::AddRemoteCandidates
->TransportController::AddRemoteCandidates_n
->P2PTransportChannel::AddRemoteCandidate
->P2PTransportChannel::SortConnectionsAndUpdateState
->P2PTransportChannel::MaybeSwitchSelectedConnection
->P2PTransportChannel::SwitchSelectedConnection
SignalReadyToSend SignalSelectedCandidatePairChanged
三、执行连接检查
可以参考该状态机。当连接检查失败,会启动重新收集candidate信息。
// messages for queuing up work for ourselves
enum {
MSG_SORT_AND_UPDATE_STATE = 1,
MSG_CHECK_AND_PING,
MSG_REGATHER_ON_FAILED_NETWORKS,
MSG_REGATHER_ON_ALL_NETWORKS
};
四、选择选定的对并启动媒体
进行探测,收到对端的报文的时候,就会发送该信号量,选定传输方式。
AsyncUDPSocket::OnReadEvent发送信号量SignalReadPacket
->AllocationSequence::OnReadPacket
->UDPPort::HandleIncomingPacket
->UDPPort::OnReadPacket
->Connection::OnReadPacket
->StunRequestManager::CheckResponse
->ConnectionRequest::OnResponse
->Connection::OnConnectionRequestResponse
::Connection::ReceivedPingResponse[set_write_state(STATE_WRITABLE)]
::Connection::MaybeUpdateLocalCandidate[SignalStateChange]
UpdateNetworkCost->SignalStateChange:
在多网卡时,对wifi、4G、vpn等类型设置不同权重值。当检测出权重高的网络可以通的时候,进行切换。
set_connected->SignalStateChange TCP链接成功后,会发送这个信号。
UpdateReceiving->SignalStateChange
HandleBindingRequest->SignalStateChange
五、心跳检测
(加密时传输密钥,暂时没有接触到)