RTCPeerConnection API
是每一個瀏覽器之間點對點鏈接的核心,RTCPeerConnection
是WebRTC
組件,用於處理對等體之間流數據的穩定和有效通訊。javascript
RTCPeerConnection
能夠保護Web開發人員免受潛伏在其中的無數複雜性的影響。WebRTC
使用的編解碼器和協議能夠進行大量工做,即便在不可靠的網絡上也能夠進行實時通訊:java
// 建立實例 let pc = RTCPeerConnection(serverConfig);
根據你是發起者仍是被髮起對象,在鏈接的每一邊會使用稍微不一樣的方式使用RtcPeerConnection
對象。web
serverConfigconfig
配置參數中包含iceServers
參數。它是包含有關STUN
和TURN
服務器的信息的URL
對象數組,在查找ICE
候選時使用。能夠在code.google.com
找到可用的公共STUN
服務器的列表。數組
現實中,不管你的應用如何見到那,webRTC
都須要服務器,由於:瀏覽器
webRTC
客戶端(對等方)交換網絡信息;peers
交換有關天天的數據,如視頻格式和分辨率webRTC
客戶端遍歷NAT
網關和防火牆換句話說,WebRTC
須要四種類型的服務器端功能:服務器
STUN
服務器鏈接用戶信號。NAT
/防火牆遍歷。ICE
是用於鏈接對等體的框架,例如兩個視頻聊天客戶端。最初,ICE
嘗試經過UDP
直接鏈接對等端,以儘量低的延遲。在此過程當中,STUN
服務器只有一個任務:使NAT
後面的對等體可以找到其公共地址和端口。網絡
下面是調用流程:session
1.獲取本地媒體設備成功以後,建立一個新的RTCPeerConnection
對象,初始化將本地音視頻軌道加入到RTCPeerConnection框架
function createConn(stream) { localStream = stream // 顯示本地視頻流 localVideo.srcObject = stream; //谷歌公共stun服務器 let serverConfig = { "iceServers": [ { "urls": ["turn:192.168.1.133:3478"], "username": "webrtc", "credential": "webrtc" } ] }; // 呼叫者 let localPeer = new RTCPeerConnection(serverConfig) // 被呼叫者 let remotePeer = new RTCPeerConnection(serverConfig) // 設置媒體流監聽,將本地流添加到RTCPeerConnection對象 localStream.getTracks().forEach((track) => { localPeer.addTrack(track, localStream); }); localPeer.addStream(stream) }
2.註冊onicecandidate
處理程序,並監聽獲取本身的ICE
協商信息,它將任何ICE
候選發送給其餘對等方socket
function createConn(stream) { ... // 當得到到本身的公網地址後,發送給其它客戶端 localPeer.onicecandidate = function(event) { console.log('I got my icecandidate info') if (event.candidate) { console.log(event.candidate.candidate) } socket.emit('onicecandidate', event.candidate); } // 若是監測到本地媒體流鏈接到本地,將其綁定到一個video標籤上輸出 localPeer.ontrack = function(e) { // 由於媒體流是一個數組 if (remoteVideo.srcObject !== e.streams[0]) { remoteVideo.srcObject = e.streams[0]; console.log('received remote stream'); } }; }
3.提早註冊消息處理程序。信令服務器還應該有一個處理來自遠程計算機的消息處理程序。若是消息包含RTCSessionDescription
對象,則應該使用RTCSessionDescription()
方法將其添加到RTCPeerConnection
對象。若是消息包含RTCIceCandidate
對象,則應該使用addIceCandidate()
方法將其添加到RTCPeerConnection
對象。
消息處理程序會根據誰是呼叫方和被呼叫方被調用。
//呼叫方收到對方回覆的SDP時調用的消息處理程序 localPeer.setRemoteDescription(new RTCSessionDescription(answer)); //被呼叫方收到對方發送的SOP時調用的消息處理程序 localPeer.addIceCandidate(new RTCIceCandidate(candidate));
4.撥通對方,發送本身的SDP
信息,開始提供/回答協商過程,這是呼叫者的流量不一樣於被呼叫者的惟一步驟。呼叫者使用createoffer( )
方法開始協商,並註冊一個收到RTCSessiondescription
對象的回調。而後這個回調應該使用setlocaldescription( )
將這個rtcsessiondescription
對象添加到rtcpeerconnection
對象中。最後,調用者應該使用信令服務器將這個rtcsessiondescription
發送到遠程計算機。另外一方面,被呼叫者,在createanswer()
方法中註冊相同的回調。請注意,只有在從調用者收到通知後,纔會啓動流。
//當本地開始撥打對方的時候,發送本身的SDP信息 const offerOptions = { offerToReceiveAudio: 1, offerToReceiveVideo: 1 }; function call() { console.log('Starting call'); try { console.log('localPeerConnection createOffer start'); const offer = await pc1.createOffer(offerOptions); console.log(offer); localPeer.setLocalDescription(offer) socket.emit('offer', offer); } catch (e) { console.log(`Failed to create session description: ${e.toString()}`); } } // 當本地收到對方的撥號通知時 收到對方的SDP信息,而後生成回覆SDP信息 function handleOffer(offer, name) { connectedUser = name; console.log("I got offer: "); localPeer.setRemoteDescription(new RTCSessionDescription(offer)); //create an answer to an offer localPeer.createAnswer(function(answer) { localPeer.setLocalDescription(answer); console.log("I will reply a answer") send({ type: "answer", answer: answer }); }, function(error) { alert("Error when creating an answer"); }); }; // 當撥號方收到對方回覆的SDP後,設置到鏈接中,調用消息處理程序 socket.on('answer', (desc) => { console.log("I got answer: ", desc.sdp); localPeerConnection.setRemoteDescription(desc); })