webRTC实现1v1连接的基本流程
A端与B端
A端:
1、连接信令服务器 (socket)
2、创建RTCPeerConnection实例myPc,通过getUserMedia 获取到本地的音视频流,遍历流中的track(轨,一个媒体流里面有多个轨)addTrack添加到myPc中去
navigator.getUserMedia({ video: true, audio: true }, (stream) => {
const myPc = new RTCPeerConnection();
stream.getTracks().forEach((track) => {
myPc.addTrack(track, stream);
});
myPc.ontrack = (e) => {
console.log("获取到数据", e.streams);
};
});
3、调用myPc.createOffer创建一个offer的SDP(A端的媒体相关描述信息) ,调用setLocalDescription把这个SDP设置到localDescription。
const option = {
//iceRestart:true,
offerToReceiveVideo: 1,
offerToReceiveAudio: 0,
};
myPc?.createOffer(option)
.then((offer)=>{myPc.setLocalDescription(offer);})
.catch(...);
//监听候选者的两种写法
addEventListener("icecandidate", (event) => {});
myPc.onicecandidate = (event) => {};
之后底层会发送一个请求(bindrequest) 给stun/turn服务,然后就开始收集所有可以与B连接的候选者(网络地址信息),同时还会把SDP发送给信令服务器,信令服务器再中转给B
B端:
B拿到了offer的SDP之后创建一个RTCPeerConnection实例BmyPc(连接对象)。
调用BmyPc.setRemoteDescription将这个SDP设置进去。并使用BmyPc.createAnswer创建一个应答给A,这个时候也会产生B本机的媒体相关信息 AnswerSDP。
调用BmyPc.setLocalDescription将AnswerSDP设置进去。B的协商就完成了,有远端A的SDP也有自己本地的SDP。
之后底层会发送一个请求bind request给stun/turn服务,收集所有可以与A连接的候选者,同时还会把AnswerSDP发送给信令服务器,由信令服务器中转给A
A端:
拿到B返回的AnswerSDP,调用myPc.setRemoteDescription设置到remoteDescription**
**
到这里A跟B的媒体协商动作就完成了🎉
之前A给sturn/turn发送过bind request收集候选者,通过onIceCandidate监听接收到候选者信息,A将候选者信息发送给信令服务器,通过信令服务器转给B
function sendmessage(roomid, data) {
console.log("send p2p message:", roomid, data);
socket?.emit("message", room, data);
}
socket.on("message", (roomid, data) => {
myPc.onicecandidate = (e) => {
if (e.candidate) {
sendmessage(room, {
type: "candidate",
label: e.candidate.sdpMLineIndex,
id: e.candidate.sdpMid,
candidate: e.candidate.candidate,
});
}
};
}
B端:
接收到A的候选者信息,使用addIceCandidate添加到连接通路的列表中。
socket.on("message", (roomid, data) => {
if(data.type==="candidate"){
var candidate = new RTCIceCandidate({
sdpMLineIndex: data.label,
candidate: data.candidate,
});
BmyPc.addIceCandidate(candidate);
}
}
B也给sturn/turn也发送过bind request收集候选者,通过onIceCandidate接收到候选者信息,将候选者发送给信令服务器,通过信令服务器转给A
A端:
接收到B的候选者信息,addIceCandidate添加到连接通路的列表中
(这时候AB双方都拿到对方所有的互通的候选者,这时候底层就会做连接检测:先形成一个个的candidate-pair,排序后进行连接检测,找到一个最优的通路之后 AB就进行通讯了)
A-B进行通讯A给B发送数据,B端onAddStream监听收到数据流之后,前面已经绑定好了connection,收到数据之后需要将数据addStream添加进来,才能进行音视频的渲染(addtrack 和 ontrack 是最新的API, 慢慢onAddStream和 addstream 就不用了)