本文以同一個瀏覽器的RTCPeerConnection爲例,來說明媒體協商的過程。多個瀏覽器的流程也是一樣的,只不過媒體協商的信息以消息的形式發送到對端,而且還要包括p2p連接的建立等。
1 媒體協商流程
1 首先發起端要創建一個offer,並調用setLocalDescription設置本地的SDP
2 然後通過信令服務器將含有SDP的offer設置給對端
3 對端拿到此offer以後調用setRemoteDescription將此SDP信息保存
4 對端創建一個answer,並調用setLocalDescription設置本地的SDP
5 通過信令服務器將含有SDP的answer發送給發起端
6 發起端調用setRemoteDescription將此SDP信息保存
2 代碼示例
效果演示
首先初始化控件,定義成員變量,給控件添加點擊事件
var localVideo = document.querySelector('video#localvideo');
var remoteVideo = document.querySelector('video#remotevideo');
var btnStart = document.querySelector('button#start');
var btnCall = document.querySelector('button#call');
var btnHangup = document.querySelector('button#hangup');
var offerSdpTextarea = document.querySelector('textarea#offer');
var answerSdpTextarea = document.querySelector('textarea#answer');
var localStream;
var pc1;
var pc2;
btnStart.onclick = start;
btnCall.onclick = call;
btnHangup.onclick = hangup;
點擊start按鈕開始獲取視頻流並顯示
function start(){
if(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia){
console.error('the getUserMedia is not supported!');
return;
}else {
var constraints = {
video:true,
audio:false
}
navigator.mediaDevices.getUserMedia(constraints)
.then(getMediaStream)
.catch(handleError);
btnStart.disabled = true;
btnCall.disabled = false;
btnHangup.disabled = true;
}
}
獲取到視頻流則賦值給顯示控件,獲取失敗則打印日誌
function getMediaStream(stream){
localVideo.srcObject = stream;
localStream = stream;
}
function handleError(err){
console.error('Failed to get Media Stream!', err);
}
點擊call按鈕,執行call方法。
function call(){
//1 首先創建本地和對端的RTCPeerConnection對象pc1和pc2,
pc1 = new RTCPeerConnection();
pc2 = new RTCPeerConnection();
//2 然後給pc1和pc2添加接收ice的回調監聽,當收到對端的ice後添加到各自的ice中
pc1.onicecandidate = (e) =>{
pc2.addIceCandidate(e.candidate);
}
pc2.onicecandidate = (e) =>{
pc1.addIceCandidate(e.candidate);
}
//3 p2接收到視頻流以後顯示視頻
pc2.ontrack = getRemoteStream;
//4 本地流遍歷所有軌track,並添加到pc1的track中。
localStream.getTracks().forEach((track)=>{
pc1.addTrack(track, localStream);
});
//5 配置offer選項
var offerOptions = {
offerToRecieveAudio:0,
offerToRecieveVideo:1
}
//6 本地創建offer 並設置offer創建成功的回調
pc1.createOffer(offerOptions)
.then(createOfferSuc)
.catch(handleOfferError);
btnCall.disabled = true;
btnHangup.disabled = false;
}
遠端接收到視頻流以後播放視頻
function getRemoteStream(e){
remoteVideo.srcObject = e.streams[0];
}
pc1 offer創建成功的回調
function createOfferSuc(desc){
//1 首先調用pc1的setLocalDescription
pc1.setLocalDescription(desc);
offerSdpTextarea.value = desc.sdp;
//2 調用pc2的setRemoteDescription
pc2.setRemoteDescription(desc);
//3 遠端創建answer, 並設置answer創建成功的回調
pc2.createAnswer()
.then(createAnswerSuc)
.catch(handleAnswerError);
}
pc2 answer創建成功的回調
function createAnswerSuc(desc){
//1 首先調用pc2的setLocalDescription
pc2.setLocalDescription(desc);
answerSdpTextarea.value = desc.sdp;
//2 調用
pc1.setRemoteDescription(desc);
}
此時pc1和pc2都已經調用了setLocalDescription和setRemoteDescription。完成了媒體協商的過程。本地和遠端的視頻都能正常顯示。