webRTC入门(端对端连接的基本流程)

310 阅读2分钟

webRTC实现1v1连接的基本流程

端到端连接流程.png

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 就不用了)