WebRTC(十二) Web端媒体协商


本文以同一个浏览器的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。完成了媒体协商的过程。本地和远端的视频都能正常显示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章