有用的网址:
https://webrtc.org/
WebRTC API - Web API 接口参考 | MDN
Browser APIs and Protocols: WebRTC - High Performance Browser Networking(O'Reilly)
浏览器中查看webrtc运行的实时信息:
Chrome浏览器:chrome://webrtc-internals/
Firefox浏览器:about:webrtc
解析webrtc dump:Import webrtc-internals dumps
一、WebRTC简介
WebRTC:Web Real-Time Communication,网页即时通信。WebRTC是一个谷歌开源项目,由一组标准、协议和JavaScript API组成,用于实现浏览器之间(端到端)的音频、视频及数据共享,不再需要借助任何插件。
WebRTC可简单理解为:一个支持网页浏览器进行实时音频或视频对话的API,即音视频处理+及时通讯的开源库。
WebRTC的特点:
1.开源、免费,开发者不需要承担高昂的专利费用。
2.基于浏览器,不需要安装插件,只要调用就可以实现音视频互动。
3.被纳入了HTML5标准,主流浏览器全面支持 WebRTC。
最常见的 WebRTC 场景很可能是两个浏览器都运行相同的 Web 应用程序(从相同的网页下载),如下图:
WebRTC web 应用程序(通常以 HTML 和 JavaScript 的混合形式编写) 通过标准化的 WebRTC API 与 web 浏览器交互,从而允许它适当地利用和控制实时浏览器功能,如下图:
二、WebRTC相关概念
WebRTC中,有三个主要的知识点,分别是:
- MediaStream:获取音频和视频流
- RTCPeerConnection:音频和视频数据通信
- RTCDataChannel:应用数据通信
WebRTC 通信过程中的四种角色:
- Signal Server
- ICE/TURN/STUN Server
- Remote Peer
- Local Peer
WebRTC 通信过程中的基本概念:
- Room:Signal Server使用Room的概念对同一组通信的peers进行配对管理,一个room中包含有1个或者多个peers。当没有peers存在时room销毁;当第一个peer连接到signal server时执行create room动作,此时因为没有其他peers,建立room的这个peer不与其他节点建立P2P通信;其他peers随后加入room,加入room后会主动与room已经存在的peer建立连接;
- Offer:主动与其他peer建立P2P链接的peer把自己的SDP信息整理好,通过signaling server转发给room里面的其他peer,这个SDP信息包就是Offer;
- Answer:被动连接的Peer在收到signaling server转发的其他peer的offer信息以后,也把自己的SDP信息整理好,同样通过signal server转发给主动连接它的peer,他自己的SDP信息包就是Answer;
- IceCandidate:Peer与ICE/TURN/STUN Server建立连接,获取自己的NAT类型以及外网IP和端口,这些ICE/TURN/STUN Server返回的消息就是IceCandidate;
三、WebRTC通信流程
对于上图中描述的PeerConnection建立的完整流程进行以下说明(上图是以ClientA主动向ClientB发起连接为例):
1.首先ClientA和ClientB连接到Signal Server上(如通过WebSocket连接);
2. ClientA在本地通过GetUserMedia获取本地媒体设备的数据,并创建PeerConnection对象,调用其AddStream方法把本地的Media添加到PeerConnection对象中。
(对于ClientA而言,既可以在与Signaling Server建立连接之前就创建并初始化PeerConnection如阶段1,也可以在建立Signaling Server连接之后创建并初始化PeerConnection如阶段2;ClientB既可以在上图的1阶段也可以在2阶段做同样的事情,访问自己的本地接口并创建自己的PeerConnection对象。)
3.通信由ClientA发起,所以ClientA调用PeerConnection的CreateOffer接口创建自己的SDP offer,ClientA通过PeerConnection的SetLocalDescription方法将该SDP对象保存起来,并把这个SDP Offer信息通过Signal Server通道中转发给ClientB;
4. ClientB收到Signaling Server中转过来的ClientA的SDP信息也就是offer后,通过PeerConnection的SetRemoteDescription方法将其保存起来。然后调用CreateAnswer创建自己的SDP信息也就是answer,并通过PeerConnection的SetLocalDescription的方法保存该应答SDP,并把这个answer通过Signal server转发给ClientA;
5. ClientA收到转发的answer消息,将其通过PeerConnection的SetRemoteDescription方法保存起来;
6. 在offer/answer流程中,ClientA和ClientB开始收集candidate信息。ClientA通过自己PeerConnection创建时传递的参数等待来自于ICE server的通信,获取自己的candidate,当candidate available的时候会自动回调PeerConnection的OnIceCandidate;
7. ClientA通过Signling Server发送自己的Candidate给ClientB,ClientB依据同样的逻辑把自己的Candidate通过Signaling Server中转发给ClientA;
8. 检查ICE Candidate的连接状态,选择可用的Candidate。
9. DTLS协商秘钥,用于RTP数据的加密和解密
在 WebRTC 中使用 DTLS 的地方包括两部分:协商和管理 [SRTP]密钥和为 [DataChannel]提供加密通道。
至此ClientA和ClientB通过PeerConnection建立连接,P2P通道建立。
四、WebRTC API
1. 获取本地媒体设备的音视频:navigator.mediaDevices.getUserMedia()
用法:
const constraints = {
'video': true,
'audio': true
}
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
console.log('Got MediaStream:', stream);
})
.catch(error => {
console.error('Error accessing media devices.', error);
});
2. 屏幕共享:avigator.mediaDevices.getDisplayMedia()
3. 建立对等连接:new RTCPeerConnection()
示例:
var pc_config = webrtcDetectedBrowser === 'firefox' ?
{'iceServers':[{'urls':'stun:23.21.150.121'}]} : // IP address
{'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]};
var pc_constraints = {
'optional': [
{'DtlsSrtpKeyAgreement': true}
]};
pc = new RTCPeerConnection(pc_config, pc_constraints);
RTCPeerConnection.createOffer() / RTCPeerConnection.createAnswer()进行媒体协商
语法:aPromise = pc.createOffer([options]);
在交换sdp信息的同时,ice信息也在进行交换,通过交换ice信息,最终会选择一种合适的方式来建立连接(p2p或者基于turn服务器的延时转发通路)
每当发现新的候选对象(即IP,port tuple)时,ICE 代理就会自动将其注册到 RTCPeerConnection 对象,并通过回调函数(onIceCandidate)通知应用程序。 该应用程序可以决定在发现每个候选者之后(Trickle ICE)尽快将其转移到远程方,或者决定等待 ICE 收集阶段完成,然后立即发送所有候选者。
pc.onicecandidate = handleIceCandidate;
RTCPeerConnection.createDataChannel()
语法:dataChannel = RTCPeerConnection.createDataChannel(label[, options]);
返回一个RTCDataChannel对象,RTCDataChannel有send()和close()方法实现数据的发送
五、非媒体数据通信
使用DTLS与SCTP协议实现安全的可靠传输,可与媒体数据共用一个传输层端口。
The standardization work within the IETF has reached a general consensus on the usage of the Stream Control Transmission Protocol (SCTP) encapsulated in DTLS to handle nonmedia data types.
如下图抓包为连续多次发送字符串"dfdfdeedd"
如果没有createOffer() 则不会进行ice协商