浏览器自己不支持相互之间直接创建信道进行通讯,都是经过服务器进行中转。好比如今有两个客户端,甲和乙,他们俩想要通讯,首先须要甲和服务器、乙和服务器之间创建信道。甲给乙发送消息时,甲先将消息发送到服务器上,服务器对甲的消息进行中转,发送到乙处,反过来也是同样。这样甲与乙之间的一次消息要经过两段信道,通讯的效率同时受制于这两段信道的带宽。同时这样的信道并不适合数据流的传输,如何创建浏览器之间的点对点传输,一直困扰着开发者。javascript
WebRTC 是一个开源项目,旨在使得浏览器能为实时通讯(RTC)提供简单的 JavaScript 接口。WebRTC 不只可传输视频,也能够传输其余数据例如文本、图片等。须要注意的是,WebRTC 并非浏览器的一个子集,浏览器只是根据 WebRTC 的标准协议实现了 WebRTC 的原生接口。Android 和 IOS 系统也支持 WebRTC 。html
WebRTC 应用包括下面四个主要的概念:java
信令服务器(Signalling servers)web
ICE 服务器(ICE servers)segmentfault
媒体服务器 (Media servers)浏览器
JavaScript 接口 (JavaScript API)服务器
信令服务器主要用于在两个用户之间交换信息。虽然 WebRTC 是点对点通讯,但仍是须要服务器来初始化链接,并传递一些信息。
WebRTC 没有定义用于创建信道的信令的协议,所以可使用任意的传输方式,例如 WebSocket, XMPP, SIP, AJAX。网络
你可使用实时的传输协议好比 WebSocket 来交换数据,也可使用简单的 GET/POST 方式轮询服务器来获取数据。ide
信令服务器传送的数据有:google
协商媒体功能和设置
标识和验证会话参与者的身份
控制媒体会话、指示进度、更改会话和终止会话
其中只有第一项的必备功能。其余均可以根据业务需求自由调整。
媒体协商最重要的功能在于,为参与点对点通讯的两个浏览器之间交换会话描述协议(SDP)。SDP 包含浏览器的 RTP 媒体栈配置所需的所有信息,包括媒体类型(音频、视频、数据)、所需的编解码器,用于编解码器的哥哥参数或设置,以及有关带宽的信息。此外,信令通道还用于交换候选地址,以便进行 ICE 打洞。
实现点对点通讯的关键在于两个浏览器之间能直接发送和接收数据包,但通常状况下,浏览器或手机都是经过路由器访问 Internet,因此存在网络地址转换(NAT)。位于 NAT 以内的 IP 地址是私有地址,外部没法访问。分配给 NAT 的 IP 地址才是公共地址。NAT 每次从内部到外部转发数据包时都使用公共地址。
交互式创建链接(ICE)是一种标准穿透协议,它利用 STUN 和 TURN 服务器来创建链接。
STUN 服务器能够遍历 NAT,获取浏览器的候选地址,包括私有地址、外层 NAT 的公共 IP 地址等。通讯信令通道能够交换候选地址,浏览器一旦发送并收到了候选项,就会开始进行链接检查,若检查成功,便使用该候选项发送媒体。
在大多状况下,经过穿透能够创建直接对等链接。可是,若 NAT 或防火墙限制很是严格,没法创建链接,就只能经过 TURN 服务器中继媒体。
媒体服务器不是必须的,但在多方会话或须要对媒体作额外处理的状况下能够考虑加入。对于有多个浏览器参与的会议,能够采用一个集中式媒体服务器。在这种状况下,美国浏览器都只需与媒体服务器创建单个链接便可,这种结构的优点是额可以扩展很是大的会话,同时能够在最大限度上减小当有新加入者加入会话事美国浏览器所需的处理工做量。同时,媒体服务器也可对媒体进行分析、处理、保存等工做。
经过调用 navigator.getUserMedia() 能够获取视频或音频的数据,constraints 参数能够选择是否获取视频音频。下面是一个简单的示例
var constraints = { audio: false, video: true }; var video = document.querySelector('video'); function successCallback(stream) { if (window.URL) { video.src = window.URL.createObjectURL(stream); } else { video.src = stream; } } function errorCallback(error) { console.log('navigator.getUserMedia error: ', error); } navigator.getUserMedia(constraints, successCallback, errorCallback);
RTCPeerConnection 是 WebRTC 中最重要的一个接口,用于肯定 ICE 服务器、交换 SDP。链接过程以下:
建立 RTCPeerConnection 对象
RTCPeerConnection 的参数用于肯定 ICE 服务器,下面是使用了 google 开放的 STUN 服务器
let iceServer = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] }; let pc = new RTCPeerConnection(servers);
将媒体流放入 RTCPeerConnection 对象中
pc.addStream(localStream);
经过 offer 和 answer 交换 SDP 描述符
甲和乙各自创建一个PC实例
甲经过 PC 所提供的 createOffer() 方法创建一个包含甲的 SDP 描述符的 offer 信令
甲经过 PC 所提供的 setLocalDescription() 方法,将甲的SDP描述符交给甲的 PC 实例
甲将 offer 信令经过服务器发送给乙
乙将甲的 offer 信令中所包含的的SDP描述符提取出来,经过PC所提供的 setRemoteDescription() 方法交给乙的PC实例
乙经过PC所提供的 createAnswer() 方法创建一个包含乙的 SDP 描述符 answer 信令
乙经过PC所提供的 setLocalDescription() 方法,将乙的 SDP 描述符交给乙的PC实例
乙将answer信令经过服务器发送给甲
甲接收到乙的answer信令后,将其中乙的SDP描述符提取出来,调用setRemoteDescripttion()方法交给甲本身的PC实例
ICE 打洞
当网络候选可用时,经过信令服务器将其发送到对方浏览器
pc.onicecandidate = function(event) { if (event.candidate) { sendToServer(event.candidate) } };
当接受到对方网络候选时,将其加入
let candidate = new RTCIceCandidate(candidate); pc.addIceCandidate(candidate);
监听对方发送的媒体是否可用,并播放媒体
pc.onaddstream = event => { remoteVideo.src = window.URL.createObjectURL(event.stream); }
RTCDataChannel 是 RTCPeerConnection API 的一部分,只有在建立了 RTCPeerConnection 实例后才能建立数据通道。数据通道能够用于发送文本或是文件。
pc = new RTCPeerConnection(); dc = pc.createDataChannel('dc'); dc.onmessage = event => console.log(event.data); dc.send('text'); dc.sed(new arraybuffer(32))
在另外一端可使用 ondatachannel 得到 RTCDataChannel 对象
pc.ondatachannel = event => dc = event.channel;
https://codelabs.developers.g...