peerconnect-client与server信令获取和交互流程
原因:上个文章只是介绍了一下client和server端的简单协议交互,并没有涉及到webRTC的信令交互.即offer,answer,candidate等。
概述:webRTC的通信为点对点,则每个点都会创建自己的offer和candidate发送给对端,对端收到后创建自己的answer和candidate进行回复。然后webRTC内部进行candidate连通测试。下面利用代码进行简单描述。
接上文获取在线列表成员,然后点击成员进行连接调用代码如下,通过代码可以看出首先进行创建PeerConnection对象,然后创建本地的audio_track,video_track及准备需要的Mediastream.然后初始化成功后调用CreateOffer方法.
void Conductor::ConnectToPeer(int peer_id) {
LOG(INFO) << __FUNCTION__;
RTC_DCHECK(peer_id_ == -1);
RTC_DCHECK(peer_id != -1);
if (peer_connection_.get()) {
main_wnd_->MessageBox("Error",
"We only support connecting to one peer at a time", true);
return;
}
if (InitializePeerConnection()) {
peer_id_ = peer_id;
peer_connection_->CreateOffer(this, NULL);
} else {
main_wnd_->MessageBox("Error", "Failed to initialize PeerConnection", true);
}
}
当CreateOffer成功后则内部会进行事件回调,事件主要定义在CreateSessionDescriptionObserver中.通过定义可以看出主要实现回调为CreateOffer和CreateAnswer.
// CreateOffer and CreateAnswer callback interface.
class CreateSessionDescriptionObserver : public rtc::RefCountInterface {
public:
// This callback transfers the ownership of the |desc|.
// TODO(deadbeef): Make this take an std::unique_ptr<> to avoid confusion
// around ownership.
virtual void OnSuccess(SessionDescriptionInterface* desc) = 0;
virtual void OnFailure(const std::string& error) = 0;
protected:
~CreateSessionDescriptionObserver() {}
};
客户端实现OnSuccess方法后,将本机回调接收到Offer信息信息调用SetLocalDescription进行保存,随后发送给服务端.主要代码和数据信息如下
void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc) {
LOG(INFO) << __FUNCTION__;
peer_connection_->SetLocalDescription(
DummySetSessionDescriptionObserver::Create(), desc);
std::string sdp;
desc->ToString(&sdp);
Json::StyledWriter writer;
Json::Value jmessage;
jmessage[kSessionDescriptionTypeName] = desc->type();
jmessage[kSessionDescriptionSdpName] = sdp;
SendMessage(writer.write(jmessage));
LOG(INFO) << jmessage;
}
{
"sdp" : "v=0\r\no=- 449280690799912824 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS stream_label\r\nm=audio 9 UDP/TLS/RTP/SAVPF 103 104 0 8 106 105 13 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:cF8F\r\na=ice-pwd:/mLl0OIRuzAUE0gXyCJ+Z+P4\r\na=fingerprint:sha-256 79:B2:E3:E0:8A:0C:CB:DA:D2:12:D6:50:FB:FD:B5:E8:18:CA:C6:F6:07:26:0E:F7:CF:53:7F:80:E4:76:73:3B\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:2929087609 cname:O025nGVLc6C+RI1k\r\na=ssrc:2929087609 msid:stream_label audio_label\r\na=ssrc:2929087609 mslabel:stream_label\r\na=ssrc:2929087609 label:audio_label\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 98 100 102 127 97 99 101 125\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:cF8F\r\na=ice-pwd:/mLl0OIRuzAUE0gXyCJ+Z+P4\r\na=fingerprint:sha-256 79:B2:E3:E0:8A:0C:CB:DA:D2:12:D6:50:FB:FD:B5:E8:18:CA:C6:F6:07:26:0E:F7:CF:53:7F:80:E4:76:73:3B\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtpmap:100 H264/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:102 red/90000\r\na=rtpmap:127 ulpfec/90000\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:125 rtx/90000\r\na=fmtp:125 apt=102\r\na=ssrc-group:FID 4198811712 3825804760\r\na=ssrc:4198811712 cname:O025nGVLc6C+RI1k\r\na=ssrc:4198811712 msid:stream_label video_label\r\na=ssrc:4198811712 mslabel:stream_label\r\na=ssrc:4198811712 label:video_label\r\na=ssrc:3825804760 cname:O025nGVLc6C+RI1k\r\na=ssrc:3825804760 msid:stream_label video_label\r\na=ssrc:3825804760 mslabel:stream_label\r\na=ssrc:3825804760 label:video_label\r\n",
"type" : "offer"
}
而Candidate的回调主要实现是通过OnIceCandidate事件,该事件定义在PeerConnectionObserver中.当收集到一个candidate后就会进行回调,然后将Candidate数据发送给服务端进行转发,可以看出candidate的回调为多次。
// PeerConnection callback interface, used for RTCPeerConnection events.
// Application should implement these methods.
class PeerConnectionObserver {
public:
// A new ICE candidate has been gathered.
virtual void OnIceCandidate(const IceCandidateInterface* candidate) = 0;
std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {}
protected:
// Dtor protected as objects shouldn't be deleted via this interface.
~PeerConnectionObserver() {}
};
{
"candidate" : "candidate:1347174600 1 udp 2122260223 192.168.27.196 50715 typ host generation 0 ufrag oBB3 network-id 3 network-cost 50",
"sdpMLineIndex" : 0,
"sdpMid" : "audio"
}
当服务器接收到数据信息后进行转发,这时客户端的hanging_get对象的OnHangingRead将被触发.然后将数据通过OnMessageFromPeer进行解析.通过如下代码可以看出获取的数据有两种类型一种是有type类型,一种是没有type类型。而有type类型的数据就是对端的offer或者answer.则接收后则会调用SetRemoteDescription进行保存。如果是没有type类型则是candidate信息,则调用AddIceCandidate进行保存.然后webrtc内部就会进行ice连接测试,然后开始点对点通信。
void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) {
rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type);
if (!type.empty()) {
LOG(INFO) << " Received session description :" << message;
peer_connection_->SetRemoteDescription(
DummySetSessionDescriptionObserver::Create(), session_description);
if (session_description->type() ==
webrtc::SessionDescriptionInterface::kOffer) {
peer_connection_->CreateAnswer(this, NULL);
}
return;
} else {
if (!peer_connection_->AddIceCandidate(candidate.get())) {
LOG(WARNING) << "Failed to apply the received candidate";
return;
}
LOG(INFO) << " Received candidate :" << message;
return;
}
}
总结:以上流程就是简单的信令协议交互,端点之间传递自己的Candidate和Offer或者Answer,然后实现点对点通信,webRtc暴露出的接口想对来说较为简单,下一步分析一下Candidate数据信息含义。
上一篇: webrtc打开默认摄像头