Web Real-Time Communication(Web实时通信,WebRTC)由一组标准、协议和JavaScript API组成,用于实现浏览器之间(端到端)的音频、视频及数据共享。

WebRTC使得实时通信变成一种标准功能,任何Web应用都无需借助第三方插件和专有软件,而是通过简单地JavaScript API即可完成。

在WebRTC中,有三个主要的知识点,理解了这三个知识点,也就理解了WebRTC的底层实现原理。这三个知识点分别是:

  • MediaStream:获取音频和视频流
  • RTCPeerConnection:音频和视频数据通信
  • RTCDataChannel:任意应用数据通信

MediaStream

如上所说,MediaStream主要是用于获取音频和视频流。其JS实现也比较简单,代码如下:

'use strict';

navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia; var constraints = { // 音频、视频约束
audio: true, // 指定请求音频Track
video: { // 指定请求视频Track
mandatory: { // 对视频Track的强制约束条件
width: {min: 320},
height: {min: 180}
},
optional: [ // 对视频Track的可选约束条件
{frameRate: 30}
]
}
}; 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);

  

在JS中,我们通过getUserMedia函数来处理音频和视频,该函数接收三个参数,分别是音视频的约束,成功的回调以及失败的回调。

在底层,浏览器通过音频和视频引擎对捕获的原始音频和视频流加以处理,除了对画质和音质增强之外,还得保证音频和视频的同步。

由于音频和视频是用来传输的,因此,发送方还要适应不断变化的带宽和客户端之间的网络延迟调整输出的比特率。

对于接收方来说,则必须实时解码音频和视频流,并适应网络抖动和时延。其工作原理如下图所示:

如上成功回调的stream对象中携带者一个或多个同步的Track,如果你同时在约束中设置了音频和视频为true,则在stream中会携带有音频Track和视频Track,每个Track在时间上是同步的。

stream的输出可以被发送到一或多个目的地:本地的音频或视频元素、后期处理的JavaScript代理,或者远程另一端。如下图所示:

RTCPeerConnection

在获取到音频和视频流后,下一步要做的就是将其发送出去。但这个跟client-server模式不同,这是client-client之间的传输,因此,在协议层面就必须解决NAT穿透问题,否则传输就无从谈起。

另外,由于WebRTC主要是用来解决实时通信的问题,可靠性并不是很重要,因此,WebRTC使用UDP作为传输层协议:低延迟和及时性才是关键。

在更深入讲解之前,我们先来思考一下,是不是只要打开音频、视频,然后发送UDP包就搞定了?

当然没那么简单,除了要解决我们上面说的NAT穿透问题之外,还需要为每个流协商参数,对用户数据进行加密,并且需要实现拥塞和流量控制。

我们来看一张WebRTC的分层协议图:

ICE、STUN和TURN是通过UDP建立并维护端到端连接所必需的;SDP 是一种数据格式,用于端到端连接时协商参数;DTLS用于保障传输数据的安全;SCTP和SRTP属于应用层协议,用于在UDP之上提供不同流的多路复用、拥塞和流量控制,以及部分可靠的交付和其他服务。

ICE(Interactive Connectivity Establishment,交互连接建立):由于端与端之间存在多层防火墙和NAT设备阻隔,因此我们需要一种机制来收集两端之间公共线路的IP,而ICE则是干这件事的好帮手。

  • ICE代理向操作系统查询本地IP地址
  • 如果配置了STUN服务器,ICE代理会查询外部STUN服务器,以取得本地端的公共IP和端口
  • 如果配置了TURN服务器,ICE则会将TURN服务器作为一个候选项,当端到端的连接失败,数据将通过指定的中间设备转发。

WebRTC使用SDP(Session Description Protocol,会话描述协议)描述端到端连接的参数。
SDP不包含媒体本身的任何信息,仅用于描述"会话状况",表现为一系列的连接属性:要交换的媒体类型(音频、视频及应用数据)、网络传输协议、使用的编解码器及其设置、带宽及其他元数据。

DTLS对TLS协议进行了扩展,为每条握手记录明确添加了偏移字段和序号,这样就满足了有序交付的条件,也能让大记录可以被分段成多个分组并在另一端再进行组装。
DTLS握手记录严格按照TLS协议规定的顺序传输,顺序不对就报错。最后,DTLS还要处理丢包问题:两端都是用计时器,如果预定时间没有收到应答,就重传握手记录。
为保证过程完整,两端都要生成自己签名的证书,然后按照常规的TLS握手协议走。但这样的证书不能用于验证身份,因为没有要验证的信任链。因此,在必要情况下,
应用必须自己参与各端的身份验证:

  • 应用可以通过登录来验证用户
  • 每一端也可以在生成SDP提议/应答时指定各自的"身份颁发机构",等对端接收到SDP消息后,可以联系指定的身份颁发机构验证收到的证书

SRTP为通过IP网络交付音频和视频定义了标准的分组格式。SRTP本身并不对传输数据的及时性、可靠性或数据恢复提供任何保证机制,
它只负责把数字化的音频采样和视频帧用一些元数据封装起来,以辅助接收方处理这些流。

SCTP是一个传输层协议,直接在IP协议上运行,这一点跟TCP和UDP类似。不过在WebRTC这里,SCTP是在一个安全的DTLS信道中运行,而这个信道又运行在UDP之上。
由于WebRTC支持通过DataChannel API在端与端之间传输任意应用数据,而DataChannel就依赖于SCTP。

以上讲了这么多,终于到我们的主角RTCPeerConnection,RTCPeerConnection接口负责维护每一个端到端连接的完整生命周期:

  • RTCPeerConnection管理穿越NAT的完整ICE工作流
  • RTCPeerConnection发送自动(STUN)持久化信号
  • RTCPeerConnection跟踪本地流
  • RTCPeerConnection跟踪远程流
  • RTCPeerConnection按需触发自动流协商
  • RTCPeerConnection提供必要的API,以生成连接提议,接收应答,允许我们查询连接的当前状态,等等

我们来看一下示例代码:

var signalingChannel = new SignalingChannel();
var pc = null;
var ice = {
"iceServers": [
{ "url": "stun:stun.l.google.com:19302" }, //使用google公共测试服务器
{ "url": "turn:user@turnserver.com", "credential": "pass" } // 如有turn服务器,可在此配置
]
};
signalingChannel.onmessage = function (msg) {
if (msg.offer) { // 监听并处理通过发信通道交付的远程提议
pc = new RTCPeerConnection(ice);
pc.setRemoteDescription(msg.offer);
navigator.getUserMedia({ "audio": true, "video": true }, gotStream, logError);
} else if (msg.candidate) { // 注册远程ICE候选项以开始连接检查
pc.addIceCandidate(msg.candidate);
}
}
function gotStream(evt) {
pc.addstream(evt.stream);
var local_video = document.getElementById('local_video');
local_video.src = window.URL.createObjectURL(evt.stream);
pc.createAnswer(function (answer) { // 生成描述端连接的SDP应答并发送到对端
pc.setLocalDescription(answer);
signalingChannel.send(answer.sdp);
});
}
pc.onicecandidate = function (evt) {
if (evt.candidate) {
signalingChannel.send(evt.candidate);
}
}
pc.onaddstream = function (evt) {
var remote_video = document.getElementById('remote_video');
remote_video.src = window.URL.createObjectURL(evt.stream);
}
function logError() { ... }

  

DataChannel

DataChannel支持端到端的任意应用数据交换,就像WebSocket一样,但是是端到端的。
建立RTCPeerConnection连接之后,两端可以打开一或多个信道交换文本或二进制数据。

其示例demo如下:

var ice = {
'iceServers': [
{'url': 'stun:stun.l.google.com:19302'}, // google公共测试服务器
// {"url": "turn:user@turnservera.com", "credential": "pass"}
]
}; // var signalingChannel = new SignalingChannel(); var pc = new RTCPeerConnection(ice); navigator.getUserMedia({'audio': true}, gotStream, logError); function gotStream(stram) {
pc.addStream(stram); pc.createOffer().then(function(offer){
pc.setLocalDescription(offer);
});
} pc.onicecandidate = function(evt) {
// console.log(evt);
if(evt.target.iceGatheringState == 'complete') {
pc.createOffer().then(function(offer){
// console.log(offer.sdp);
// signalingChannel.send(sdp);
})
}
} function handleChannel(chan) {
console.log(chan);
chan.onerror = function(err) {}
chan.onclose = function() {}
chan.onopen = function(evt) {
console.log('established');
chan.send('DataChannel connection established.');
} chan.onmessage = function(msg){
// do something
}
} // 以合适的交付语义初始化新的DataChannel
var dc = pc.createDataChannel('namedChannel', {reliable: false}); handleChannel(dc);
pc.onDataChannel = handleChannel; function logError(){
console.log('error');
}

  原文:https://segmentfault.com/a/1190000011403597

仅供个人学习和交流

深入理解WebRTC的更多相关文章

  1. (三)WebRTC手记之本地视频采集

    转自:http://www.cnblogs.com/fangkm/p/4374610.html 前面两篇文章介绍WebRTC的运行流程和使用框架接口,接下来就开始分析本地音视频的采集流程.由于篇幅较大 ...

  2. WebRTC手记之本地视频采集

    转载请注明出处:http://www.cnblogs.com/fangkm/p/4374610.html 前面两篇文章介绍WebRTC的运行流程和使用框架接口,接下来就开始分析本地音视频的采集流程.由 ...

  3. 揭开webRTC媒体服务器的神秘面纱——WebRTC媒体服务器&开源项目介绍

    揭开webRTC媒体服务器的神秘面纱--WebRTC媒体服务器&开源项目介绍 WebRTC生态系统是非常庞大的.当我第一次尝试理解WebRTC时,网络资源之多让人难以置信.本文针对webRTC ...

  4. WebRTC 学习资源 电子书 WebRTC权威指南 Learning WebRTC

    webRTC源码下载地址:https://pan.baidu.com/s/18CjClvAuz3B9oF33ngbJIw 提取码:wl1e 1.<WebRTC权威指南>第三版 中文版 本书 ...

  5. webrtc源码阅读理解一

    webrtc是一个比较成熟的实时音视频处理开源项目,一上来老大就扔给我一本webrtc native实践,虽然狠下心"翻"完了一遍,但是还是云里雾里的,在经过几个月的摸索之后,我大 ...

  6. WebRTC学习之ICE深入理解

    ICE(交互式连接建立---Interactive Connectivity Establishment),是一种标准穿透协议.它利用STUN和TURN服务器来帮助端点建立连接.下图显示了ICE的基本 ...

  7. 使用WebRTC搭建前端视频聊天室——数据通道篇

    本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...

  8. 单独编译使用WebRTC的音频处理模块

    块,每块个点,(12*64=768采样)即AEC-PC仅能处理48ms的单声道16kHz延迟的数据,而 - 加载编译好的NS模块动态库 接下来只需要按照 此文 的描述在 android 的JAVA代码 ...

  9. WebRTC通信流程

    WebRTC是HTML5支持的重要特性之一,有了它,不再需要借助音视频相关的客户端,直接通过浏览器的Web页面就可以实现音视频对聊功能.而且WebRTC项目是开源的,我们可以借助WebRTC源码快速构 ...

随机推荐

  1. Spark机器学习基础-特征工程

    对连续值处理 0.binarizer/二值化 from __future__ import print_function from pyspark.sql import SparkSession fr ...

  2. 图片上传怎么用File接受文件

    xl_echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.——这才是真正的堪称强大!! - ...

  3. 【转载】Sqlserver根据生日计算年龄

    在Sqlserver中,可以根据存储的出生年月字段计算出该用户的当前年龄信息,主要使用到DateDiff函数来实现.DateDiff函数的格式为DATEDIFF(datepart,startdate, ...

  4. elementUI表单验证

    elementUI表单验证非常方便,我们直奔主题: <template> <el-form ref="orderForm" :model="orderF ...

  5. Nginx 之 Rewrite 规则

    write 规则介绍 Rewite 规则作用 Rewrite规则可以实现对url的重写,以及重定向 作用场景: URL访问跳转,支持开发设计,如页面跳转,兼容性支持,展示效果等 SEO优化 维护:后台 ...

  6. Android笔记(二十二) Android中的GridView

    GridView和ListView一样,是Android中比较常见的布局控件,譬如我们的手机桌面其实就是一个GridView. 效果: 实现过程和ListView类似,也是通过Adapter将数据源展 ...

  7. c# 处理串行化对象的版本变化

  8. c# 属性成员

  9. 虚拟机更改MAC

    有两种方式修改MAC地址 方法一 现实中网卡一出厂就有MAC地址,虚拟机的MAC地址见下图,这个就相当于出厂MAC.在这里修改MAC相当于直接修改硬件MAC 方法二 这里修改MAC,硬件MAC并没有变 ...

  10. Shell脚本字符串匹配及日常命令工具 - 用法总结(技巧指南)

    Shell提供了很多字符串和文件处理的命令,如awk.expr.grep.sed等命令,还有文件的排序.合并和分割等一系列的操作命令.下面重点总结下Shell字符串处理.文本处理以及各类命令及函数用法 ...