什么是WebRTC
WebRTC 即Web Real-Time Communication(网页实时通信)的缩写,是一个支持网页浏览器之间进行实时数据传输(包括音频、视频、数据流)的技术。经过多年的发展与改进,日臻成熟,作为浏览器网页端的通信技术,WebRTC与H5巧妙结合,使得网页端的音视频通信变的简单易行。
WebRTC有哪些优点
- 免费:WebRTC本身是开源的,使用WebRTC本身是免费的。此外WebRTC是可以不借助媒体服务器实现简单的点对点音视频通信,减少额外花费。
- 无插件:不需要安装任何软件,大家只要打开浏览器,输入一个url,即可实现多人音视频通话。
- 跨平台:由于是基于浏览器进行音视频通话,各个平台只要有浏览器即可。
- 控制灵活:WebRTC没有指定具体的信令协议,具体的信令协议留给应用程序实现,这就方便了开发者根据自己的需求方便灵活的实现各种音视频业务场景。
- 接合HTML5:HTML5自身的能力能够为WebRTC提供灵活快捷的音视频数据的二次处理,可以实现丰富的业务功能。
- 易入门:WebRTC是'JavaScript'引擎库,允许web开发者只使用几个简单的api就能够基于浏览器轻易快捷开发出丰富的实时多媒体应用,无需关注多媒体的数字信号处理过程,只需要编写简单的JavaScript即可,大大的降低了音视频开发的门槛。
WebRTC距离商用还有多少距离
- 信令控制协议的开发:上面说明过WebRTC并没有实现信令协议,这既带来了灵活,也带来了挑战,想实现一套满足商业应用业务的信令并不容易。
- 跨平台的挑战:即对浏览器使用不便,或者不支持浏览器(各种盒子或者嵌入式设备)的实际环境的兼容。
- 音视频设备的适配:音视频设备支持的能力不同,需要自己的WebRTC产品做复杂的适配处理,才能满足自己的业务场景。
- 浏览器限制:
- 并非所有的浏览器都支持WebRTC,具体请参考浏览器兼容性 ;
- 各个浏览器厂商工业实现上的兼容。对于WebRTC,各大浏览器厂商实现的并不完全一致,比如说Safari浏览器不支持VP8系列视频编码,一些安卓移动设备上Chrome无法使用H264视频编码,还有其他很多细节问题,想要实现各种平台,各种浏览器之间无障碍的互通,还需要很多工作要做;
- 浏览器版本更迭的兼容,浏览器本身也是在不停的更新对WebRTC的工业实现,也不断更新对HTML5的使用,这些更新对于我们的WebRTC产品也是一大挑战。
- 需要各种服务器的支持:现实情况中,WebRTC应用需要信令服务器、媒体服务器、中继服务器的支持,才能实现信令的有效稳定传输、NAT的穿越、媒体的合理路由和转发,进而保障稳定、高质量的音视频通话。而且针对大并发量的使用场景,需要合理的媒体处理框架设计,用于保证音视频服务的可靠性、稳定性。
为什么选择云信
- 专业:
- 研发资历成熟,19年通信领域研发深耕,亿级产品线上验证,移动端方案优化7年以上;
- 全球节点覆盖异地多机房服务集群,覆盖全球范围,架构灵活高并发自动水平扩容;
- 消息必达策略采用动态智能DNS掉线快速重连机制,消息排重持续重连直至到达,保障通信的接通率;
- 海量资源支持全球超500个CDN节点,超10000个分布式转码集群,千万播放并发,存储、宽带无上限。
- 接入和使用灵活:网易云信提供即时通讯云和视频云技术的PaaS层服务,以快速集成SDK的模式为开发者提供稳定易用的技术支撑,客户可以方便快捷地接入,全面满足自己的业务需求。
- 全平台支持:支持iOS、Android、Windows、Web、Linux、MacOS、微信小程序等主流平台观看、互动及互通,支持点对点、多人实时音视频通话和旁路直播等功能。
- IM信令:网易云通信IM服务基于网易19年的IM技术积累,致力于打造最稳定的即时通讯平台。 IM服务提供了一整套即时通讯基础能力,通过该平台服务就可以将即时通讯、实时网络能力快速集成至企业自身应用中。使用IM信令作为WebRTC产品的信令协议必定能满足用户的各种需求。
- WebRTC SDK的能力:云信SDK兼容各大浏览器,各种版本,对于用户而言所有的浏览器类型,所有的版本都是一致的,所有的差异由SDK统一解决,对用户不可见。
WebRTC相关知识点
关于WebRTC首先明确一些内容:
WebRTC利用浏览器中的JavaScript API和HTML5
WebRTC客户端之间可以进行点对点的媒体和数据传输
webrtc使用sdp协议作为媒体协商协议
webrtc使用ice作为nat穿越的手段
WebRTC 标准API
- getUserMida:通过getUserMida的API能够通过设备的摄像头和话筒获得视频、音频的同步流;
- 允许约束媒体能力
- 获取的媒体流可以输出到video标签在web页面上展示;
- 获取的媒体流可以输出到一个RTCPeerConnection中,用于编码、发送到对端;
- 可以使用HTML5本身的能力对音频、视频做二次处理,比如混频、混频、变声、调色能,将处理后的媒体在推送给对端;
- 可以本地录制获取到媒体流,也可以把获取到媒体流用于他出;
- RTCPeerConnection:RTCPeerConnection(免费下载《WebRTC 1.0: 浏览器间实时通讯》中文版)是WebRTC用于构建点对点之间稳定、高效的流传输的媒体终端;
- 进行sdp交换协商媒体
- 使用ice进行nat穿透
- dtls协商加密秘钥
- srtp加密媒体
- 媒体编解码,媒体收发
- 丢包补偿、回声抵消、带宽自动调整、动态抖动缓冲、噪声抑制与抑制等
- RTCDataChannel:RTCDataChannel(免费下载《WebRTC 1.0: 浏览器间实时通讯》中文版)使得浏览器之间(点对点)建立一个高吞吐量、低延时的信道,用于传输任意数据;
- 利用RTCPeerConnection会话
- 自定义可靠和不可靠通道
- dtls
- 阻塞控制
WebRTC点对点音视频通信过程
- 使用getUserMida接口获取本地mic、camera上音频流和视频流
- 本地初始化一个RTCPeerConnection实例
- 将通过getUserMida接口获取的本地音频流和视频流,展示到html页面上,并且添加到RTCPeerConnection实例中
- 通过RTCPeerConnection实例获取本端的sdp信息(本地媒体描述信息)
- 通过信令协议把本地的sdp发送到对端
- 通过RTCPeerConnection实例,获取本地媒体通道地址,然后通过信令协议发送到对端
- 接收对端的sdp信息、媒体通道地址,然后设置到RTCPeerConnection实例中,这样就完成了媒体协商
- 从RTCPeerConnection实例中获取对端的媒体流,可以展示到html页面上
经过上面的步骤,双方就能进行点对点视频通话了,后续的nat穿透、dtls协商加密秘钥、srtp加密媒体、媒体编解码,媒体收发都由浏览器自动完成。
Chrome屏幕共享功能的实现
上面说明获取摄像头的媒体流是通过getUserMida接口,而获取屏幕共享则是通过其他的方式; - 使用getDisplayMedia接口(chrome 72版本开始支持)
使用方式同getUserMedia接口一致,代码如下:
if (navigator.getDisplayMedia) {
return navigator.getDisplayMedia({video: true});
} else if (navigator.mediaDevices.getDisplayMedia) {
return navigator.mediaDevices.getDisplayMedia({video: true});
}
- 通过插件的方式
- 自己编写extension插件扩展,使用chrome.desktopCapture.chooseDesktopMedia接口(插件是经过了认证的,浏览器不会阻止其运行),调用这个接口时,浏览器弹出包含各种共享内容(包括屏幕、应用列表、chrome标签页)的弹窗。用户可以选择自己想要共享的内容,选定之后,该接口会返回相应的chromeMediaSourceId,然后使用getUserMeida接口把chromeMediaSourceId作为约束条件,就能够获取到共享的媒体流。
插件代码如下:
chrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
const sources = message.sources;
const tab = sender.tab;
chrome.desktopCapture.chooseDesktopMedia(sources, tab, streamId => {
if (!streamId) {
sendResponse({
type: 'error',
message: 'Failed to get stream ID'
});
} else {
sendResponse({
type: 'success',
streamId: streamId
});
}
});
return true;
}
);
chrome.runtime.onInstalled.addListener(function(){
chrome.declarativeContent.onPageChanged.removeRules(undefined, function(){
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({ pageUrl:
{ urlContains: 'app.netease.im'}})
],
actions: [new
chrome.declarativeContent.ShowPageAction()]
}
]);
});
});
getUserMedia接口的使用如下:
chrome.runtime.sendMessage(EXTENSION_ID, { sources: ['window', 'screen', 'tab'] }, {}, response => {
if (response && response.type === 'success') {
const constraint = {
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: response.streamId
}
}
}
return
navigator.mediaDevices.getUserMedia(constraint)(constraint)
.then(stream => {
console.log('获取到演示流:', stream.id)
})
}
})
Chrome 72版本unified plan适配
对WebRTC而言,Unified Plan、Plan B、Plan A是SDP中多路媒体流的协商方式,在72版本中Chrome替换了Plan B,默认使用Unified Plan。
https://webrtc.github.io/samples/src/content/peerconnection/pc1/, { iceServers: [], iceTransportPolicy: all, bundlePolicy: balanced, rtcpMuxPolicy: require, iceCandidatePoolSize: 0, sdpSemantics: "unified-plan" },
- Plan B:sdp中,一个m行描述多路media stream,以msid 作为区分;
...
a=group:BUNDLE audio
a=msid-semantic: WMS stream-id-2 stream-id-1
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
a=mid:audio
...
a=rtpmap:103 ISAC/16000
...
a=ssrc:10 cname:cname
a=ssrc:10 msid:stream-id-1 track-id-1
a=ssrc:10 mslabel:stream-id-1
a=ssrc:10 label:track-id-1
a=ssrc:11 cname:cname
a=ssrc:11 msid:stream-id-2 track-id-2
a=ssrc:11 mslabel:stream-id-2
a=ssrc:11 label:track-id-2
- Unified Plan:sdp中,一个m行对应一个meida stream;
...
a=group:BUNDLE 0 1
a=msid-semantic: WMS
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
a=mid:0
...
a=sendrecv
a=msid:- <track-id-1>
...
a=rtpmap:103 ISAC/16000
...
a=ssrc:10 cname:cname
a=ssrc:10 msid: track-id-1
a=ssrc:10 mslabel:
a=ssrc:10 label:track-id-1
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...
a=mid:1
...
a=sendrecv
a=msid:- track-id-2
...
a=rtpmap:103 ISAC/16000
...
a=ssrc:11 cname:cname
a=ssrc:11 msid: track-id-2
a=ssrc:11 mslabel:
a=ssrc:11 label:track-id-2
一、点对点视频通话业务
1、WebRTC产品中没有处理过sdp中的msid属性
不用适配,此次的更新对你的产品没有影响
2、WebRTC产品中有处理sdp中的msid属性
需要适配,凡是针对msid的判断和修改都需要废弃,重新处理
二、多流业务,使用了simulcast
1、WebRTC产品中没有处理过sdp中的msid属性
需要适配,调整接口使用,调整sdp的解析处理,增加多m行的处理
2、WebRTC产品中有处理sdp中的msid属性
需要适配,凡是针对msid的判断和修改都需要废弃,重新处理,调整接口使用,调整sdp的解析处理,增加多m行的处理
WebRTC调试
Chrome浏览器查看WebRTC状态方法:
chrome:chrome://webrtc-internals
浏览器中输入chrome://webrtc-internals,界面显示如下:
WebRTC状态图
WebRTC状态图说明: 最上面一排依次是:getUserMedia API、二个peerconnection API
- 点击查看getUserMedia API,简单说明如下:
Caller origin: https://webrtc.github.io
Caller process id: 15364
Audio Constraints
Video Constraints
{width: {min: 300, max: 640}, height: {min: 200, max: 480}}
- Audio Constraints:表示从麦克风获取视屏流的参数;
Video Constraints:表示从摄像头获取视屏流的参数;
PeerConnection状态图
PeerConnection状态图说明:
- 最上面的一行:表示peerconnection,大括号中的内容是peerconnection的配置参数,可以看到chrome已经用unified-plan替代了plan B;
- 左上角的Event:peerconnection的内部接口,对应的是内部接口
- transceiverAdded:添加getUserMeida接口获取的媒体流
- transceiverModified: 接收对端的媒体流
- createOffer:浏览器生成的本地sdp
- setLocalDescription:设置本地sdp
- setRemoteDescription:设置远端sdp
- signalingstatechange:peerconnection的状态(免费下载《WebRTC 1.0: 浏览器间实时通讯》中文版)icegatheringstatechange:本地ice候选地址收集的状态(免费下载《WebRTC 1.0: 浏览器间实时通讯》中文版)
- icecandidate:候选地址的收集接口
- iceconnectionstatechange:ICE连通性检查的状态(免费下载《WebRTC 1.0: 浏览器间实时通讯》中文版)
- 右上角的EventStats Tables:是媒体通道的具体信息,数据实时更新
- bweforvideo (VideoBwe):视频带宽相关信息
- googActualEncBitrate:视频编码器实际编码的码率,通常这与目标码率是匹配的。
- googAvailableReceiveBandwidth:视频数据接收可用的带宽。
- googAvailableSendBandwidth:视频数据发送可用的带宽。
- googBucketDelay:Google为了处理大数据速率的策略表示,通常是很小的数值。
- googRetransmitBitrate:如果RTX被使用的话,表示重传的码率。
- googTargetEncBitrate:视频编码器的目标比特率。
- googTansmitBitrate:实际发送的码率,如果此数值与googActualEncBitrate有较大的出入,可能是fec的影响。
- googCertificate:两端使用的DTLS证书、指纹和哈希算法等
- googComponent:表示认证数据与连接之间的关系,展示当前活跃的候选项对,以及有关用语DTLS和SRTP加密的相关信息。
- Conn-video-1-0 (googCandidatePair):RTP通道相关信息
- googActiveConnection:当前的连接是否活跃
- bytesReceived:接收的字节数(rtp数据)
- bytesSent:发送的的字节数(rtp数据)
- packetsSent:发送的数据包数(rtp数据)
- requestsSent、responsesSent、requestsReceived、responsesReceived:STUN请求和应答数量
- googRtt:最近的STUN请求的往返时间
- googLocalAddress:本地的候选地址
- googRemoteAddress:远端的候选地址
- googTransportType:传输通道的类型,通常是udp,即使当前正在使用tcp的连接方式通过turn中继服务器转发媒体,只有当ICE-TCP被选用时,这里才会是tcp
- Conn-video-1-1 (googCandidatePair):RTCP通道相关
- ssrc_2052494919_send (ssrc):音频发送通道相关信息
- audioInputLevel:mic采集的音频能量值
- audioOutputLevel:扬声器播出的音频能力值
- bytesSent:发送的音频数据字节数
- mediaType:媒体类型
- packetsSent:发送的音频包数
- ssrc:音频rtp包的ssrc
- googCodecName:音频编码名称
- googJitterReceived:收到了多少的抖动
- googRtt:是发送端从接受端发送过来的RTCP Receiver Report中得到的时间戳通过计算得到的往返时延
- ssrc_4160516329_send (ssrc):视频发送通道相关信息
- bytesSent:发送视频包的自己数
- codecImplementationName:视频编码器的名称
- framesEncoded:累计编码出来的视频帧数
- mediaType:媒体类型
- packetsLost:丢包数
- packetsSent:发送的视频包数
- qpSum:QP数目
- ssrc:视频rtp包的ssrc
- googTrackId:描述视频数据轨迹,这个id可以在SDP中,以及本地或远端媒体流轨道中被找到
- googAdaptationChanges:发送端因为CPU的负载变化导致的分辨变高或者变低的次数,需要设置googCpuOveruseDetection
- googAvgEncodeMs:发送端平均编码时间,越小越好。
- googBandwidthLimitedResolution:是否因为带宽受限而降低发送的视频分辨率
- googCodecName:视频编码名称
- googCpuLimitedResolution:是否因为cpu不足而降低发送的视频分辨率
- googEncodeUsagePercent:发送端(平均每帧编码时间)/(平均每帧采集时间),反应编码效率
- googFirsReceived:收到的fir请求
- googFrameHeightSent、googFrameWidthSent:发送的视频分辨率
- googFrameRateInput、googFrameRateSent:视频帧率
- googHasEnteredLowResolution:是否已经降低了视频分辨率
- googNacksReceived:收到的nack请求
- googPlisReceived:收到的pli请求
- googRtt:是发送端从接受端发送过来的RTCP Receiver Report中得到的时间戳通过计算得到的往返时延
- transportId,是指向被用于传送RTP流的部分,可以从sdp总找到
- bweforvideo (VideoBwe):视频带宽相关信息
- 左下角的部分:也是媒体通道的具体信息,以图表的形式展示,与右上角的EventStats Tables一一对应
- bweforvideo (VideoBwe):视频带宽相关信息
- googActualEncBitrate:视频编码器实际编码的码率,通常这与目标码率是匹配的。
- googAvailableReceiveBandwidth:视频数据接收可用的带宽。
- googAvailableSendBandwidth:视频数据发送可用的带宽。
- googBucketDelay:Google为了处理大数据速率的策略表示,通常是很小的数值。
- googRetransmitBitrate:如果RTX被使用的话,表示重传的码率。
- googTargetEncBitrate:视频编码器的目标比特率。
- googTansmitBitrate:实际发送的码率,如果此数值与googActualEncBitrate有较大的出入,可能是fec的影响。
- googCertificate:两端使用的DTLS证书、指纹和哈希算法等
- googComponent:表示认证数据与连接之间的关系,展示当前活跃的候选项对,以及有关用语DTLS和SRTP加密的相关信息。
- Conn-video-1-0 (googCandidatePair):RTP通道相关信息
- googActiveConnection:当前的连接是否活跃
- bytesReceived:接收的字节数(rtp数据)
- bytesSent:发送的的字节数(rtp数据)
- packetsSent:发送的数据包数(rtp数据)
- requestsSent、responsesSent、requestsReceived、responsesReceived:STUN请求和应答数量
- googRtt:最近的STUN请求的往返时间
- googLocalAddress:本地的候选地址
- googRemoteAddress:远端的候选地址
- googTransportType:传输通道的类型,通常是udp,即使当前正在使用tcp的连接方式通过turn中继服务器转发媒体,只有当ICE-TCP被选用时,这里才会是tcp
- Conn-video-1-1 (googCandidatePair):RTCP通道相关
- ssrc_2052494919_send (ssrc):音频发送通道相关信息
- audioInputLevel:mic采集的音频能量值
- audioOutputLevel:扬声器播出的音频能力值
- bytesSent:发送的音频数据字节数
- mediaType:媒体类型
- packetsSent:发送的音频包数
- ssrc:音频rtp包的ssrc
- googCodecName:音频编码名称
- googJitterReceived:收到了多少的抖动
- googRtt:是发送端从接受端发送过来的RTCP Receiver Report中得到的时间戳通过计算得到的往返时延
- ssrc_4160516329_send (ssrc):视频发送通道相关信息
- bytesSent:发送视频包的自己数
- codecImplementationName:视频编码器的名称
- framesEncoded:累计编码出来的视频帧数
- mediaType:媒体类型
- packetsLost:丢包数
- packetsSent:发送的视频包数
- qpSum:QP数目
- ssrc:视频rtp包的ssrc
- googTrackId:描述视频数据轨迹,这个id可以在SDP中,以及本地或远端媒体流轨道中被找到
- googAdaptationChanges:发送端因为CPU的负载变化导致的分辨变高或者变低的次数,需要设置googCpuOveruseDetection
- googAvgEncodeMs:发送端平均编码时间,越小越好。
- googBandwidthLimitedResolution:是否因为带宽受限而降低发送的视频分辨率
- googCodecName:视频编码名称
- googCpuLimitedResolution:是否因为cpu不足而降低发送的视频分辨率
- googEncodeUsagePercent:发送端(平均每帧编码时间)/(平均每帧采集时间),反应编码效率
- googFirsReceived:收到的fir请求
- googFrameHeightSent、googFrameWidthSent:发送的视频分辨率
- googFrameRateInput、googFrameRateSent:视频帧率
- googHasEnteredLowResolution:是否已经降低了视频分辨率
- googNacksReceived:收到的nack请求
- googPlisReceived:收到的pli请求
- googRtt:是发送端从接受端发送过来的RTCP Receiver Report中得到的时间戳通过计算得到的往返时延
- transportId,是指向被用于传送RTP流的部分,可以从sdp总找到
- bweforvideo (VideoBwe):视频带宽相关信息
网易云信翻译了W3C推荐标准WebRTC 1.0: Real-time Communication Between Browsers,并提供《WebRTC1.0: 浏览器间实时通讯》中文版免费下载。
本文是WebRTC工作组最新一次会议后的候选推荐标准,基于WebIDL定义了一组ECMAScript API,允许在实现了相关实时协议的浏览器或设备之间发送和接收媒体内容。同时也是对WebRTC的一个全面介绍,包括WebRTC中的各个术语,独有的概念,API的使用规范,详细的算法流程和一些注意点,并且对涉及的数据结构及其属性进行了剖析。在特定的使用场景下,草案的作者们还附上了示例代码。
- 对于WebRTC初学者,本文档可以作为学习教程,帮助你快速对WebRTC有全面且详细的了解,学习相关API的使用,其附带的示例代码也是很好的学习资料;
- 对于WebRTC资深开发者,本文档可以作为开发中的使用手册,根据所提供的函数调用链或是算法流程进行开发或bug定位;
- 对于高阶玩家,也可通过阅读本文档对WebRTC工作组反馈改进意见。
限时免费下载,WebRTC开发者必备,机不可失哦~