点对点(p2p)webRTC简介(仅个人学习)

302 阅读4分钟

WebRTC(Web Real­Time Communication)是 Google于2010以6829万美元从 Global IP Solutions 公司购买,并于2011年将其开源,旨在建立一个互联网浏览器间的实时通信的平台,让 WebRTC技术成为 H5标准之一。官网webrtc.org

各平台支持情况: image.png

所有主要的浏览器的兼容

WebRTC现在得到了所有主要浏览器的支持和采用,包括谷歌Chrome、苹果Safari、Mozilla Firefox 、QQ浏览器、360浏览器和Microsoft Edge。

IE支不支持webrtc

威胁传统音视频提供商 声网(跨国,跨印度)、即构科技、融云

WebRTC可靠性和易用性

WebRTC通过web浏览器普及会议体验,支持点击开始,并消除了额外软件的麻烦。

一、webRTC框架

image.png

作为web应用开发者,我们只要关心紫色部分。 特别是图中的 PeerConnection 为 Web 开发人员提供了一个抽象,从复杂的内部结构中抽象出来。我们只需要关注PeerConnection这个对象即可以开发音视频通话应用。(我们的p2p应用也是基于此对象实现)。

1.1、了解彼此的媒体格式(SDP)

image.png

比如:Peer­A端可支持VP8、H264多种编码格式,而Peer­B端支持VP9、H264,要保证二端都正确的编解码,最简单的办法就是取它们的交集H264。

注:有一个专门的协议 ,称为Session Description Protocol (SDP),可用于描述上述这类信息,在WebRTC中,参与视频通讯的双方必须先交换SDP信息,这样双方才能知根知底,而交换SDP的过程,也称为"媒体协商"。

1.2、网络协商(p2p通话直接用到的是stun服务器)

理想的网络情况是每个浏览器的电脑都是私有公网IP,可以直接进行点对点连接。

image.png

实际情况是:我们的电脑和电脑之间都是在某个局域网中,需要NAT(Network Address Translation,网络地址转换),显示情况如下图:

image.png

image.png

STUN

STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址

查出自己位于哪种类型的NAT之后,NAT为某一个本地端口关联的Internet端端口。

这些信息被用来在两个同时处于NAT路由器之后的主机之间创建UDP通信。

image.png

我们建立stun服务器,用一句话概括:告诉我你的公网IP地址+端口是什么。

ICEInteractive Connectivity Establishment,交互式连接建立协议,用于在两个主机之间建立连接,它可以在两个主机之间建立连接,即使它们之间的防火墙阻止了直接连接。(可以不借助一个公网 server 完成端到端(Peer to peer,P2P)的通信)。

二、代码应用层面具体流程

简单的框架图

image.png

2.1、创建RTCPeerConnection对象

// 创建一条由本地计算机到远端的 WebRTC 连接
const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.voipbuster.com ' }], //stun服务器
})

2.2、挂载视频流

创建两个video标签

<video id="local" autoplay playsinline muted></video>
<video id="remote" autoplay playsinline></video>

采集视频流

// 初始化
const init = async () => {
  // 获取本地端视频标签
  const localVideo = document.getElementById('local') as HTMLVideoElement
  // 获取远程端视频标签
  const remoteVideo = document.getElementById('remote') as HTMLVideoElement
  // 获取本地媒体流
  localStream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true,
  })
  // 设置本地视频流
  localVideo.srcObject = localStream
  // 添加本地流到 pc
  localStream.getTracks().forEach((track) => {
    pc.addTrack(track, localStream)
    console.log(pc);
  })

  // 监听远程流:
  pc.ontrack = (event) => {
    remoteVideo.srcObject = event.streams[0]
  }
}

2.3、创建连接

1、创建offer(提案)

// 创建 offer(提案)
const createOffer = async () => {
  const offer = await pc.createOffer()
  console.log(offer);
  await pc.setLocalDescription(offer)
  // await pc.setLocalDescription()
  // 到这里,我们本地的 offer 就创建好了,一般在这里通过信令服务器发送 offerSdp 给远端

   //setLocalDescription后,创建 ice 候选 (ice candidates)
  // 监听 RTCPeerConnection 的 onicecandidate 事件,当 ICE 服务器返回一个新的候选地址时,就会触发该事件
  pc.onicecandidate = async (event) => {
    console.log(pc)
    if (event.candidate) {
      offerSdp.value = JSON.stringify(pc.localDescription)
    }
  }
}

offer的内容: 包含一个类型字段和sdp字符串 image.png

打印一下sdp image.png

查看分配的ip + 端口 image.png

正如我们上面所说,sdp相当于一个身份证,保留了你所有的基本信息,所以参与视频通话的前提是交换这些信息。

2、远端创建answer

接受方拿到出传过来的offer,就可以在本地创建answer,然后更新到RTCPeerConnection对象中

// 创建 answer
const offerSdp2 = ref('')
const createAnswer = async () => {
  // 解析字符串
  const offer = JSON.parse(offerSdp2.value) //A端offer
  pc.onicecandidate = async (event) => {
    // Event that fires off when a new answer ICE candidate is created
    if (event.candidate) {
      answerSdp.value = JSON.stringify(pc.localDescription)
    }
  }
  await pc.setRemoteDescription(offer) //将A端的offer设置成B端的远端description
  const answer = await pc.createAnswer() //B端生成answer
  await pc.setLocalDescription(answer) // 在B端设置本地的descriptiona
}

查看B端的远程描述,其中就包含A端的ip和端口

image.png

image.png

再查看B端的本地描述

image.png

image.png

3、A端收到answer, 设置到远程端的描述中

// 添加 answer(应答)
const answerSdp2 = ref('')
const addAnswer = async () => {
  const answer = JSON.parse(answerSdp2.value)
  if (!pc.currentRemoteDescription) {
    pc.setRemoteDescription(answer)
  }
}

这时候的远端描述,和B端的ip和端口号相同

image.png

image.png

设置完成以后,通讯成功!

一个简单的webRTC的p2p的流程就完成了。

三、注意事项

3.1、公网环境下,webRTC只能在https环境。

本文代码部分来自这篇文章,需要代码得请看原文! juejin.cn/post/716553…