南昌做网站市场报价,嵌入式软件开发工程师是做什么的,30_10_郑州网站制作,wordpress数学公式4 WebRTC
4.1 历史 相信读者都有过使用Tencent QQ或者FaceTime进行视频通话的经历#xff0c;这样的应用场景相当典型和流行#xff0c;但是基本上来说它们都是每个公司推出的私有产品#xff0c;而且通信等协议也都是保密的#xff0c;这使得一种产品的用户基本上不可能… 4 WebRTC
4.1 历史 相信读者都有过使用Tencent QQ或者FaceTime进行视频通话的经历这样的应用场景相当典型和流行但是基本上来说它们都是每个公司推出的私有产品而且通信等协议也都是保密的这使得一种产品的用户基本上不可能同其他产品的用户进行视频通信。还有一些更大的应用场景那就是众多用户一起召开视频会议这比简单的点对点更为复杂很多公司已投身其中因为这一市场非常广大。 几年前笔者是很难想象这么复杂的需求和应用场景能够在Web领域中被实现但是现在Chromium和Firefox浏览器都支持Web视频通信而且神奇的是它们之间也可以相互通信听起来非常不可思议——只是需要Web开发者使用JavaScript和HTML5技术就可以完成还是免费的而且还不需要额外安装应用软件不需要额外安装插件。现在真是互联网和HTML5技术的好时代这也是HTML5的多媒体领域的一个重大进展。 WebRTCWeb Real Time Communication技术中文全称为Web实时通信技术它是一种提供实时视频通信的规范目前是W3C推荐的规范。它是一个开放的规范任何人都可以免费使用目前Chromium/Chrome和Firefox浏览器都支持了该规范。WebRTC是HTML5对多媒体支持的一个重大进展因为该技术不仅使用了音视频的输入和输出而且还涉及连接等网络连接是一个非常复杂但非常有用的技术。图11-19是一个简单的示意图说明两个支持WebRTC规范的浏览器之间是如何进行视频通信的。事实上WebRTC既允许使用服务器来进行通信也支持点对点Peer-to-Peer通信当然需要服务器的辅助。 图11-19 Chromium/Chrome和Firefox浏览器的视频通信示例图 不过很多事情并非是一蹴而就的何况这么复杂的WebRTC技术WebRTC发展至今也经历了很长的过程。首先得从一个音视频的捕获需求开始。最初HTML5希望能够提供一种捕获用户音频和视频的技术这就是getUserMedia当然刚开始也不是它而是使用下面的语句来完成音频和视频的捕获。 input typefile acceptvideo/*;capturecamcorderinput typefile acceptaudio/*;capturemicrophone但是它们太简单了只能将捕获的信息保存为一个文件或者一个快照这显然不能满足很多实际的需求之后一个新的元素定义诞生就是使用“device”元素这一元素很快被抛弃。这就是getUserMedia的前身但标准化组织很快从“device”元素转向getUserMedia它的基本使用方式是 navigator.getUserMedia({video: true, audio: true}, function (videostream) { … });思想很简单就是在navigator这个全局对象下加入一个新接口该接口使用两个参数第一表示它需要捕获视频或者音频或者两者都需要第二个是一个回调函数当捕获成功后将捕获的视频流可以输出到一个视频元素这就像是一个从服务器加载的视频文件当然它是一个视频流所以某些查找Seek操作不能工作。这里不再使用新元素而是利用原有的“video”元素实在是一个好的设计。 在这之后一个更为大胆和激进的想法诞生了就是将RTC技术引入到HTML5中来这就是WebRTC技术因为getUserMedia是入口所以自然而然地被使用到WebRTC技术的规范中来。
11.4.2 原理和规范 大家可以在脑海中想象一下如何要构建一个网络视频通信、需要哪些部分的参与及共同工作才能完成整个过程。总体上这一过程中需要三种类型的技术其一是视频其二是音频其三是网络传输。在这三种技术上具体需要以下一些部分。
音视频输入和输出设备 同音视频播放不同因为它们只是需要输出设备这里需要输入和输出设备麦克风和摄像头。同时输入使用getUserMedia技术而输出基本上可以采用音视频播放的基本框架当然需要一些额外的支持。网络连接的建立 因为视频通信需要不停地传送大量数据所以需要建立一种可靠的网络连接来让各个参与方传输数据。数据捕获、编码和发送 当用户打开设备之后需要捕获这些数据并对它们进行编码因为原始数据的数据量太大然后需要将编码后的数据通过连接传输出去。数据接收、解码和显示 接收来自其他方的数据流并进行解码然后显示出来这个需求跟播放媒体文件的需求比较类似。 根据上面的解释不难理解图11-20所描述的过程结合这些主要组成部分构成了一个比较完整的音视频通信过程。 图11-20 使用WebRTC技术的视频通信详细过程 下面了解一下规范中如何针对上面的描述来定义相应的JavaScript接口的。根据目前W3C推荐的规范草案主要包括以下几个部分。
Media Capture and Streams规范和WebRTC对它的扩展这个主要是依赖摄像头和麦克风来捕获多媒体流WebRTC对它进行扩展使得多媒体流可以满足网络传输用途也就是“video”元素可以来源于多媒体流而不仅仅是资源文件。点到点的连接也就是规范中的RTCPeerConnection接口它能够建立端到端的连接两者直接通过某种方式传输控制信息至于方式并没有进行规定。RTCDataChannel接口通过该接口通信双方可以发送任何类型的消息例如文本或者二进制数据这个不是必须的。不过这一功能极大地方便了开发者其主要思想来源于WebSocket。
11.4.3 实践——一个WebRTC例子 在介绍内部原理之前笔者希望通过剖析W3C规范中的一个例子来进一步加深对它的理解。示例代码11-5来源于W3C WebRTC规范中的示例代码笔者稍微作了一些修改以简化理解并加入注释作进一步说明。 这里主要是点对点的直接通信当然需要借助于网络提供的NAT服务其中包括三个文件第一个是双方共享的JavaScript代码第二个是发起端的HTML代码第三个是接收端的HTML代码。通常第二个和第三个可以是一样的这里为了方便理解作了少许区别。因为代码中已经作了较为详细的讲解所以后面不再赘述其中的原理。
示例代码11-5 使用WebRTC技术的P2P网络视频通信 JavaScript文件common.js// 创建消息通道例如使用XMLHttpRequest或者WebSocket。根据WebRTC规范的说明// 本身WebRTC不提供双方进行控制信息传输的通道由开发者自行选择合适的方法// 这里简单使用一个函数表示创建了一个通道该通道包含一个能够发送消息的“send”var signalChannel createSignalChannel();// 将ICE的Candidate发送给对方这个是ICE定义的主要是ICE协议用来建立连接需// 要的信息。双方需要交互这个信息function sendCandidate(candidate) {if (candidate) signalChannel.send(JSON.stringify({ candidate: candidate }));}function sendDescription() {signalingChannel.send(JSON.stringify({ sdp: conn.localDescription }));}signalingChannel.onmessage function (event) {// 如果没有建立连接需要创建在这里表明这是接受者端if (conn null) start();// 从控制信息中获取信息内容var message JSON.parse(event.data);// 如果信息类型是设置Description相关的就调用setRemoteDescriptionif (message.sdp) {conn.setRemoteDescription(new RTCSessionDescription(message.sdp), function () {// 如果受到一个请求offer需要答复它这里应该是接收方处理的if (conn.remoteDescription.type offer) {conn.createAnswer(function(desc) {conn.setLocalDescription(desc, sendDescription);});} else if (message.candidate) {conn.addIceCandidate(new RTCIceCandidate(message.candidate));}};// 用来存放RTCPeerConnection对象var conn null;// 用来显示从自身设备捕获的多媒体流var selfView document.getElementById(selfView);// 用来显示从对方传送过来的多媒体流var remoteView document.getElementById(remoteView);// 开始创建连接等function start() {// 创建连接conn new RTCPeerConnection({ iceServers: [{ url: stun:stun. example.org }] });// 保存从自身捕获的多媒体流var capturedStream null;// 捕获音视频navigator.getUserMedia({ audio: true, video: true }, function (stream) {// 将捕获的多媒体流使用“video”元素播放出来selfView.src URL.createObjectURL(stream);capturedStream stream;}// 将多媒体流加入连接conn.addStream(capturedStream);// 接收到ICE Candidate事件需要将candidate信息传送给对方conn.onicecandidate function (event) {sendCandidate(event.candidate);};// 这个是由发起者调用因为接收者不会发送该事件conn.onnegotiationneeded function() {// 创建一个Offer然后发送给接收者conn.createOffer(function (desc) {conn.setLocalDescription(desc, sendDescription););});// 将远端多媒体流使用“video”元素显示出来conn.onaddstream function (evt) {remoteView.src URL.createObjectURL(evt.stream);};}发起者HTML文件节选video idselfView autoplay /videovideo idremoteView autoplay/videoscript srccommon.js/scriptscript// 上面的两个video元素分别用来显示自己捕获的多媒体流和对方的多媒体流// 实际情况中可能是某个用户作为发起者单击了“开始”按钮启动音视频通信start();/script接受者HTML文件节选:video idselfView autoplay /videovideo idremoteView autoplay/videoscript srccommon.js typejavascript/script相信通过上面的代码介绍读者应该理解使用WebRTC构建一个P2P视频通信的基本过程这其中网络连接的部分主要基于ICE协议NAT和SDP协议以及一些支持NAT的辅助设施STUN和URN有兴趣的读者可以自行查阅相关技术文档。
4.4 WebKit和Chromium的实现 下面来看一看WebKit和Chromium是如何支持WebRTC规范的。笔者首先需要澄清一下关于WebRTC的两种解释本节中会有两种WebRTC用法一种是指WebRTC这项技术和规范另一种是WebRTC这个项目它是支持WebRTC规范的一个开源项目。默认情况下是指前者如果是指WebRTC这个开源项目笔者会明确指出。 下面来了解一下从webrtc.org上介绍的关于支持WebRTC技术的内部框架和功能模块图11-21来源于“http://www.webrtc.org/reference/architecture”的架构图但是缩减了其中一些部分。这里所示的是实现了WebRTC功能的开源项目架构图。 图11-21中主要包括三大方面即语音、视频和传输它们三个构成了WebRTC的主要组成部分。其中iSACinternet Speech Audio Codec和iLBCinternet Low Bitrate Codec是两种不同的音频编码格式是为了适应互联网的语音传输要求而存在的前者是针对带宽比较大的情况后者针对带宽较小的情况目前都是可以免费使用的。其中VP8同样是Google提供免费视频格式前面介绍过了。传输部分主要是加入了对前面协议的支持模块。在会话管理中主要使用一个开源项目libjingle来进行管理。下面灰色部分主要是WebRTC工作时依赖的下层功能的接口在Chromium浏览器中它会提供相应接口和功能给WebRTC使用。 图11-21 WebRTC项目的架构图 上面是WebRTC开源项目的架构图在Chromium中通常使用WebRTC项目来完成WebRTC规范的功能并使用libjingle项目来建立点到点的连接。所以Chromium主要的目的是将WebRTC和libjingle的能力桥接到浏览器中来先看WebRTC规范中建立连接所需要的相关基础设施图11-22是WebKit、Chromium及Chromium中使用libjingle的类的层次图。 图11-22 WebKit和Chromium建立连接的基础设施 基础设施主要分成三个层次首先是WebKit也就是最上面的部分。该部分最上面的类是RTCPeerConnection从名字就可以猜出该类是对WebRTC连接的接口类实际上它就是从规范中定义的RTCPeerConnection接口文件生成的基本框架当然真正和JavaScript引擎打交道还需要一个桥接类。该桥接类包含一个实际实现的连接类句柄m_peerHandler它是这个连接所包含的本地多媒体流和远端对方的多媒体流。读者可以想象一下视频会议的场景首先Webkit需要将本地的多媒体流收集起来通过连接传输给对方本地可以选择是否通过“video”播放。同时需要接收从对方传输过来的多媒体流这也是WebRTC的主要部分。当然还包括DataChannel相关对象这里没有标出。 至于接下来的部分就是WebKit的实现类该类能够满足RTCPeerConnection的功能要求但是它需要通过不同移植的实现才能完成因为本身WebKit的WebCore并没有这样的能力。在WebKit的Chromium中同样定义了两个类WebRTCPeerConnectionHandler和WebRTCPeerConnectionHandlerClient根据WebKit的类名定义方式前者是需要Chromium来实现而后者则是由Chromium调用并由WebKit来实现的这里主要是应用连接事件的监听函数所以WebKit能够将它们传递给JavaScript引擎。 之后是Chromium的实现类。RTCPeerConnectionHandler类继承自WebKit的Chromium移植的接口类并做了具体的实现这就是content::RTCPeerConnectionHandler它同时集成自PeerConnectionHandleBase类而该类拥有了支持建立连接所需的能力当然它是依赖于libjingle项目提供的连接能力。 libjingle提供了建立和管理连接的能力支持透过NAT和防火墙设备、代理等建立连接。libjingle不仅支持点到点的连接也支持多用户连接。同时还包含了连接所使用的MediaStream接口这是因为Chromium本身不直接使用WebRTC项目提供的接口而是调用libjingle来建立连接并使用libjingle提供的MediaStream接口而libjingle本身则会使用WebRTC项目的音视频处理引擎。 接下来要介绍的是多媒体流它需要一个非常复杂的框架首先来看WebKit是如何支持getUserMedia这个接口的。图11-23描述了WebKit以及WebKit的Chromium移植中所定义的接口图中虚线上半部分是WebKit中的类下半部分是Chromium中的类。 图11-23 WebKit支持多媒体流的基础设施 最上层是WebKit支持多媒体流编程接口提供的具体实现类如NavigatorMediaStream类而直接同V8 JavaScript引擎桥接的类是V8NavigatorUser-MediaSuccessCallback它是一个绑定类。因为getUserMedia接口主要是返回一个MediaStream对象而MediaStream类可以提供众多访问数据流的接口而连接的目的就是需要将MediaStream对应的多媒体流传输出去。图中UserMediaRequest类负责请求创建一个MediaStream对象。在WebKit的Chromium移植中定义WebUserMediaClient为一个接口类Chromium需要新建子类来实现这一功能这就是Chromium中的MediaStreamImpl类它在后面的介绍中还会出现。 WebKit中使用MediaStreamRegistry类来注册和管理对应的类管理类根据ID信息来识别各个多媒体数据流。在接口层中Chromium移植使用WebMediaStream类来表示多媒体流使用WebMediaStreamRegistry类来表示注册管理类。 下面的问题是MediaStream接口需要提供各种事件给网页因为很多实际的工作是在Chromium中来完成的所以MediaStreamImpl会将这些事件从Chromium传递给WebKit。同时因为Chromium的多进程和沙箱模型一些工作需要在Browser进程中完成所以可以见到如图11-24所描述的跨进程的基础设施。 图11-24 Chromium支持MediaStream接口基础设施 IPC左侧部分是Browser进程中的两个主要类分别是消息处理类和MediaStream的管理类该管理类知道MediaStream对应的网页是什么并将事件如创建和销毁等传回Renderer进程。右侧是消息派发类主要帮助MediaStreamImpl类来完成与Browser进程相关的MediaStream消息的传递。 实际上MediaStream可以表示本地的多媒体流也可以表示远端的多媒体流。对于本地的多媒体流需要音频和视频的捕获机制同时使用上面建立的连接传输给远端。对于远端的多媒体流需要使用连接来接收数据并使用到音频和视频的解码能力。下面分成四个部分来分别介绍。 首先是音频的捕获机制图11-25描述了该机制使用的主要类。当网页需要创建多媒体流的时候MediaStreamImpl会创建音频捕获类也就是WebRtcAudioCapturer类如图中上半部分。因为捕获音频需要音频输入设备所以使用AudioDeviceFactory工厂类创建一个逻辑上的AudioInputDevice对象。另外一个重要的类是WebRtcAudioDeviceImpl用来表示音频的设备该类继承自WebRtcAudioDeviceNotImpl类。这其实是继承自libjingle和WebRTC项目中的抽线接口的一个桥接类用来表示它们需要的音频设备当然包括输入设备。同样因为Renderer进程不能访问音频输入设备所以需要IPC来完成这一功能Browser进程的AudioInputController会控制和访问设备而AudioInputDeviceManager可以管理和控制所有输入设备。 图11-25 Chromium本地捕获音频的基础设施
其次是处理远端多媒体流中的音频解码和播放功能。图11-26是Chromium处理远端音频流所需要的一些主要类及关系图。这里不涉及连接如何接收传输的数据因为Chromium是使用libjingle和WebRTC项目来完成连接的功能。Chromium使用WebRtcAudioRender类来完成音频渲染该桥接类会被WebMediaPlayer作为渲染音频的实现类其作用主要是将MediaStream的数据同实际的音频渲染类结合起来。 图11-26 Chromium处理远端音频基础设施
再次是从视频输入设备请求捕获本地视频流图11-27是该功能依赖的一些主要类。 图11-27 Chromium本地捕获视频的基础设施 首先看虚线右侧Renderer进程中的设施。同样是MediaStreamImpl类发起由辅助工厂类MeidaStreamDependencyFactory帮助创建一个RtcVideoCapaturer用来获取视频。该类有两个作用其一是实现libjingle和WebRTC项目中的接口类因为需要视频输入的实现这个同音频部分非常类似。另外就是将调用请求交给一个代理类来完成这就是RtcVideoCaptureDelegate类。下面的就比较好理解了分别是管理类VideoCaptureImplManager和视频捕获类VideoCaptureImpl并包括一个发送消息到Browser进程的辅助类。在Browser进程使用控制类VideoCaptureController来获取VideoCaptureDevice该类会使用摄像头等视频输入设备效果都相对比较简单直观。 最后是处理远端多媒体流中的视频解码和播放功能。当MediaStreamImpl对象接收到远端的多媒体流之后它会使用WebRTC来对视频数据进行解码因为可以使用硬件来解码所以提高了处理的性能。 图11-28 Chromium处理远端视频基础设施
把WebRTC整个过程综合起来分析可以有一种更为整体和直观的感受如图11-29所示。读者可以结合这个图来回味一下之前所描述的众多细节。图中没有本地捕获的音视频的播放过程因为它们不是必须的而且同播放远端多媒体流类似这里便不再赘述。 图11-29 WebKit、Chromium、libjingle和WebRTC等项目支持WebRTC规范的框架 目前在Chrome浏览器中基于WebRTC的网页已经可以在移动操作系统如Android上获得支持移动领域的进展必将推动该技术的进一步发展。回顾本章介绍的多媒体各个方面的技术读者可以看出HTML5技术不仅引入了多媒体的支持而且加入了之前插件也不能支持的众多更新更复杂的技术但是却极大提升了HTML5的应用范围。