前言
WebRTC是当前实时通信领域的重要技术之一,具有广泛的应用前景。可以实现音频、视频和数据的实时传输。支持点对点通信、多方会议、屏幕共享等多种应用场景,同时具有高质量、低延迟、强安全性等特点,是开发实时通信应用的理想选择。可以应用于远程协作、在线教育、在线医疗、物联网等领域,具有广泛的商业应用前景。WebRTC技术包括了音视频的采集、编解码、网络传输、显示等功能,本文主要从API使用说明和注意细节方面介绍一下WebRTC的大致情况。
根据W3C的WebRTC1.0:Real-time Communication Between Browsers规范,WebRTC的源码中定义了两套主要的C++接口,分别是MediaStream与PeerConnection相关的API,MediaStream 相关API定义在源码api\media_stream_interface.h中。主要涉及这4个概念:source、sink、meidatrack、mediastream。
MediaStream API
MediaAPI中有两个重要组成:MediaStreamTrack、MediaStream。MediaStreamTrack对象代表单一类型的媒体流,产生自客户端的media source,可以是音频或者视频,但只能是其中一种,是音频称作audio track,视频的话称作video track,这其实就是我们平时所说的音轨与视频轨。
一个track由source与sink组成。source给track提供数据。
MeidiaStream用于将多个MediaStreamTrack对象打包到一起。一个MediaStream可包含audio track 与video track。类似我们平时的多媒体文件,可包含音频与视频。
一个MediaStream对象包含0或多个MediaStreamTrack对象。MediaStream中的所有MediaStreamTrack对象在渲染时必须同步。就像我们平时播放媒体文件时,音视频的同步。
简单点说,source 与sink构成一个track,多个track构成MediaStram。
source 与 sink
在MediaTrack的源码中,MediaTrack都是由对应的source和sink组成的。
浏览器中存在从source到sink的媒体管道,其中source负责生产媒体资源,包括多媒体文件,web资源等静态资源以及麦克风采集的音频,摄像头采集的视频等动态资源。而sink则负责消费source生产媒体资源,也就是通过,video等媒体标签进行展示,或者是通过RTCPeerConnection将source通过网络传递到远端。RTCPeerConnection可同时扮演source与sink的角色,作为sink,可以将获取的source降低码率,缩放,调整帧率等,然后传递到远端,作为source,将获取的远端码流传递到本地渲染。
检测获取音视频设备
使用MediaDevices 接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。可以用来取得任何硬件资源的媒体数据。提供访问链接媒体输入的设备,如摄像头、麦克风、屏幕共享等。它可以使你取得任何硬件资源的媒体数据。
通过MediaDevices的方法 enumerateDevices() 请求一个可用的媒体输入和输出设备的列表,例如麦克风,摄像机,耳机设备等。返回的 Promise 完成时,会带有一个描述设备的 MediaDeviceInfo的数组。
采集本地音视频数据
MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D 转换器等等),也可能是其他轨道类型。
它返回一个 Promise 对象,成功后会resolve回调一个 MediaStream 对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise会reject回调一个 PermissionDeniedError 或者 NotFoundError 。
视频约束
getUserMedia()函数接收一个参数MediaStreamConstraints,MediaStreamConstraints对象用于指定要请求的轨道类型(音频,视频或二者)以及(可选)每个轨道的任何要求。
约束项可以具有下面这两个属性中的一个或两个:
video—表示是否需要视频轨道audio—表示是否需要音频轨道
如果仅指定是否包含音频和视频流的时候,可以这样
设置分辨率
可以用video中的width和height属性从网络摄像头请求一定的分辨率,比如请求1280×720分辨率的视频流。直接设置的width和height会被视为“ideal”(理想)值,浏览器会尽可能的保持这个分辨率,但是也有可能会返回一个接近的分辨率,因为我们设置的分辨率可能摄像头不支持
可以用min,max和exact关键字来限制分辨率范围,从而得到最佳的分辨率
可以使用deviceId指定被用于捕捉流的设备ID。这个设备ID是唯一的,并且在同一个来源的会话中是相同的。需要首先使用MediaDevices.enumerateDevices()来获取设备id。以下是一些常用的约束条件:
MediaDevices.getSupportedConstraints()的支持。这个函数会返回一个字典,列出用户代理支持的约束:
设置码率
在 通 话 过 程 中 实 时 更 改 视 频 码 率 , 主 要 涉 及 对RTCRtpEncodingPara-meters.maxBitrate 的修改,maxBitrate 能够接受的码率单位是 bps。
兼容性问题
有一部分老的浏览器不能兼容navigator.mediaDevices.getUserMedia来获取麦克风和摄像头,可用如下来获取
Safari浏览器 不支持多个 tab getUserMedia,否则前一个 tab 会停止采集,远端流也有可能出现黑屏无声。
屏幕共享
MediaDevices 接口的 getDisplayMedia() 方法提示用户去选择和授权捕获展示的内容或部分内容(如一个窗口)在一个MediaStream里。用法和getUserMedia类似。
Safari默认只能共享整个屏幕,不支持选择应用和浏览器标签页。
设备监听
为了在应用程序中监测媒体设备的变化,WebRTC提供了devicechange事件和ondevicec-hange事件句柄,与navigator.mediaDevices结合即可实时监控媒体设备的热插拔。
视频质量调整策略
webrtc 提供了三种策略:
MAINTAIN_FRAMERATE:保帧率,降分辨率,该模式的使用场景为视频模式。
MAINTAIN_RESOLUTION: 保分辨率降帧率,使用场景为屏幕共享或者文档模式,对清晰度要求较高的场景。
BALANCED: 平衡帧率与分辨率。默认关闭,需要通过 WebRTC-Video-BalancedDegradation 开启。
webrtc API层提供了自适应策略的设置接口,通过设置 MediaStreamTrack 的 contentHint 属性就可以了。在WebRtcVideoSendStream::GetDegradationPreference 函数中会将 ContentHint 转换成 DegradationPreference。
Audio Content Hints
"speech":指定音频源为讲演,可以适当使用噪声消除或者提升源的可理解性等
"speech-recognition":指定音频源为语音识别,可以适合提高输入信号的清晰度以进行转录并关闭用于人类消费的音频处理组件
"music":指定音频源为音乐,可能意味着调整或关闭用于处理语音数据的音频处理组件,以防止音频失真
Video Content Hints
"motion":指定为运动的时候,降低分辨率以保持帧率
"detail":指定为细节的时候,降低帧率以保持分辨率,屏幕分享一般默认为细节模式
"text":指定为文本,降低帧率以保持分辨率,当编码器的文本模式可用的时候,使用文本模式。此设置通常会针对生成的单个帧中的细节进行优化,而不是平滑播放,并且可能会利用针对文本渲染进行优化的编码器工具,对于属性值为“text”的视频轨道,如果编码编解码器为AV1,则激活“text”模式的编码工具。
RTCPeerConnection API
RTCPeerConnection接口代表一个由本地计算机到远端的WebRTC连接。该接口提供了创建,保持,监控,关闭连接的方法的实现。
其接口的定义如下:
其中有一个可选参数RTCConfiguration, 在文档中定义如下;
iceServers,由多个RTCIceServer组成需要填入stun或turn服务的地址;
iceTransportPolicy :ice的传输策略,默认值是all允许考虑所有候选者,值有"all",“public” 已弃用 ,“relay” 只收集中继候选者;
rtcpMuxPolicy:收集 ICE 候选时是否使用的 RTCP 多路复用策略。值有 'negotiate’和 ‘require’;
bundlePolicy:‘balanced’、‘max-compat’和’max-bundle’;默认是balanced。
各个含义如下:
Balanced实际就是音频轨、视频轨各自各自使用一个传输通道,是分开的。其中多路音频轨是共用同一个传输通道、多路视频轨也是使用同一个通道。
max-compat是最大兼容性,怎样才能达到最大的兼容性呢?就是每一个轨都有自己的通道,如果我有这个两个音频,一个视频,就有三个通道,就是每个音频走自己的,那视频也是一样的。等到Balanced策略不成功的时候,就使用max-compat这种方式。
max-bundle就是最大化的使用一个绑定,那就是将所有的这些这个媒体的这个流都用一个这个通道进行传输。这是webrtc建议的方式,这样的话对于底层来说就比较简单了,而且你建立这个连接之后,只需要一个证书,而不需要一堆证书,否则的话,你每一个连接都需要一个证书,就会非常的耗费时间。
一般使用方式如下:
主要方法:
addIceCandidate 向ICE代理提供远程候选人。
addStream 添加MediaStream作为视频或音频的本地源。
addTrack 添加MediaStreamTrack
close 关闭连接。
createAnswer 创建answer。此方法的两个第一个参数是成功回调和错误回调。可选的第三个参数是要创建的选项。
createDataChannel 创建一个新的数据通道RTCDataChannel
createOffer 用来创建offer,创建成功后调用setLocalDescription方法将localDescription设置为offer,localDescription即为我们需要发送给应答方的sdp
getConfiguration 获取配置信息
getStats 创建一个新的RTCStatsReport,其中包含有关连接的统计信息。
removeStream 删除MediaStream作为视频或音频的本地源。
removeTrack 删除MediaStreamTrack作为视频或音频的本地源。
setLocalDescription 设置本地连接描述信息。该方法采用三个参数,RTCSessionDescription对象,成功回调,失败回调。
setRemoteDescription 设置远程连接描述信息
主要事件:
onaddstream 事件用来监听通道中新加入的流,当addstream事件被触发时,会调用此处理程序。当远程方将MediaStream添加到此连接时,会发送此事件。
ondatachannel 当数据通道事件被触发时,会调用此处理程序。将RTCDataChannel添加到此连接时发送此事件。
onicecandidate 当RTCIceCcandidate对象添加时,会发送此事件。
oniceconnectionstatechange 当iceConnectionState的值发生更改时,会发送此事件。
onnegotiationneeded 当触发需要协商的事件时,会调用此处理程序。此事件由浏览器发送,以通知将来某个时候需要进行协商。
onremovestream 当信号状态更改事件被触发时,会调用此处理程序。当signalingState的值发生变化时,会发送此事件。
onsignalingstatechange当removestream事件被激发时,会调用此处理程序。此事件是在从该连接中删除MediaStream时发送的。
ontrack当远程方将MediaStream添加到此连接时,会发送此事件。
RTCPeerConnection使用步骤如下:
1、创建一个新的 RTCPeerConnection对象,将采集到的音视频轨道,通过addTrack进行添加,发送给远端。远端可以通过监听ontrack来监听音视频的到达,并进行播放。
2、交换 SDP,交换 SDP 的目的是为了让对方知道彼此具有哪些能力,然后根据双方各自的能力进行协商,协商出大家认可的音视频编解码器、编解码器相关的参数(如音频通道数,采样率等)、传输协议等信息。创建 offer 设置为 pc1的本地描述,通过信令服务器发送到远端,作为 pc2的远端描述.pc2收到后创建answer设置成自己的本地描述,
3、收集Candidate,应答方收到发起方发送的ICE数据时,调用pc的addIceCandidate方法。pc2.addIceCandidate(new RTCIceCandidate(ice))复制代码发起方收到应答方发送的ICE数据时,同样调用RTCPeerConnection对象的addIceCandidate方法。
至此,一个最简单的WebRTC连接就建立完成了。