WebRTC 使用入门

WebRTC 是构建开放、无障碍 Web 的漫长战争中的一道新战线。

JavaScript 之父 Brendan Eich

无需插件即可实现实时通信

想象一下,您的手机、电视和电脑可以在一个通用平台上进行通信。假设您可以轻松地向 Web 应用添加视频聊天和点对点数据共享功能。这就是 WebRTC 的愿景。

想试用一下吗?WebRTC 适用于桌面版和移动版 Google Chrome、Safari、Firefox 和 Opera。不妨先试用 appr.tc 上的简单视频聊天应用:

  1. 在浏览器中打开 appr.tc
  2. 点击加入以加入聊天室,并允许应用使用您的网络摄像头。
  3. 在新标签页中打开页面末尾显示的网址,最好是在其他电脑上打开。

快速入门

没时间阅读本文或只想获取代码?

或者,您也可以直接跳转到 WebRTC Codelab,该 Codelab 以分步指南的形式介绍了如何构建完整的视频聊天应用,包括简单的信号服务器。

WebRTC 简史

网络面临的最后一个重大挑战之一是实现人与人之间的语音和视频通信:即实时通信(简称 RTC)。在 Web 应用中进行 RTC 的体验应与在文本输入框中输入文本一样自然。否则,您将无法创新,也无法开发新的互动方式。

从历史上看,RTC 一直是企业级的复杂技术,需要获得昂贵的音频和视频技术许可或自行开发。将 RTC 技术与现有内容、数据和服务集成一直以来都很困难且耗时,尤其是在 Web 上。

Gmail 视频聊天功能在 2008 年开始流行,2011 年,Google 推出了使用 Talk(与 Gmail 一样)的 Hangouts。Google 收购了 GIPS,该公司开发了 RTC 所需的许多组件,例如编解码器和回声消除技术。Google 开源了 GIPS 开发的技术,并与互联网工程任务组 (IETF) 和万维网联盟 (W3C) 的相关标准机构合作,以确保达成行业共识。2011 年 5 月,爱立信构建了 WebRTC 的第一个实现

WebRTC 实现了开放标准,可实现无插件的实时视频、音频和数据通信。需求是真实的:

  • 许多网络服务都使用了 RTC,但需要下载、原生应用或插件。其中包括 Skype、Facebook 和 Hangouts。
  • 下载、安装和更新插件非常复杂,容易出错且令人烦恼。
  • 插件难以部署、调试、排查问题、测试和维护,并且可能需要获得许可并与复杂且昂贵的技术集成。首先,要说服用户安装插件往往很难!

WebRTC 项目的指导原则是,其 API 应是开源的、免费的、标准化的、内置于网络浏览器中的,并且比现有技术更高效。

我们现在在哪里?

WebRTC 可用于各种应用,例如 Google Meet。WebRTC 还与 WebKitGTK+ 和 Qt 原生应用集成。

WebRTC 实现了以下三个 API: - MediaStream(也称为 getUserMedia) - RTCPeerConnection - RTCDataChannel

相关 API 在以下两个规范中定义:

Chrome、Safari、Firefox、Edge 和 Opera 在移动版和桌面版上均支持这三个 API。

getUserMedia:如需查看演示和代码,请参阅 WebRTC 示例,或试用 Chris Wilson 的精彩示例,其中使用 getUserMedia 作为 Web 音频的输入。

RTCPeerConnection:如需查看简单的演示和功能齐全的视频聊天应用,请分别参阅 WebRTC 示例对等连接appr.tc。此应用使用 adapter.js,这是一个 JavaScript shim,由 Google 在 WebRTC 社区的帮助下维护,用于提取浏览器差异和规范变更。

RTCDataChannel:如需了解此操作的实际运作方式,请参阅 WebRTC 示例,查看其中一个数据通道演示。

WebRTC Codelab 展示了如何使用这三个 API 构建一个用于视频聊天和文件共享的简单应用。

您的第一个 WebRTC

WebRTC 应用需要执行以下几项操作:

  • 获取在线播放的音频、视频或其他数据。
  • 获取 IP 地址和端口等网络信息,并与其他 WebRTC 客户端(称为对等方)交换这些信息,以便建立连接,即使通过 NAT 和防火墙也是如此。
  • 协调信号通信,以报告错误并启动或关闭会话。
  • 交换有关媒体和客户端功能的信息,例如分辨率和编解码器。
  • 传输流式音频、视频或数据。

为了获取和传输流式数据,WebRTC 实现了以下 API:

  • MediaStream 可访问数据流,例如来自用户摄像头和麦克风的数据流。
  • RTCPeerConnection 支持音频或视频通话,并提供加密和带宽管理功能。
  • RTCDataChannel 支持通用数据的点对点通信。

(稍后会详细介绍 WebRTC 的网络和信令方面。)

MediaStream API(也称为 getUserMedia API)

MediaStream API 表示同步的媒体串流。例如,从摄像头和麦克风输入获取的串流具有同步的视频和音频轨道。(请勿将 MediaStreamTrack<track> 元素混淆,它们是完全不同的。)

要了解 MediaStream API,最简单的方法可能是在实际应用中查看它:

  1. 在浏览器中,前往 WebRTC 示例 getUserMedia
  2. 打开控制台。
  3. 检查全局范围内的 stream 变量。

每个 MediaStream 都有输入(可能是由 getUserMedia() 生成的 MediaStream)和输出(可能会传递给视频元素或 RTCPeerConnection)。

getUserMedia() 方法接受 MediaStreamConstraints 对象参数,并返回一个解析为 MediaStream 对象的 Promise

每个 MediaStream 都有一个 label,例如 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'getAudioTracks()getVideoTracks() 方法会返回一个 MediaStreamTrack 数组。

对于 getUserMedia 示例,stream.getAudioTracks() 会返回一个空数组(因为没有音频),假设已连接正常工作的摄像头,stream.getVideoTracks() 会返回一个包含一个 MediaStreamTrack 的数组,表示来自摄像头的流式传输。每个 MediaStreamTrack 都有一种类型('video''audio')、一个 label(类似于 'FaceTime HD Camera (Built-in)'),并表示一个或多个音频或视频通道。在本例中,只有一个视频轨道,没有音频,但不难想象有更多轨道的用例,例如从前置摄像头、后置摄像头、麦克风获取数据的聊天应用,以及分享屏幕的应用。

您可以通过设置 srcObject 属性MediaStream 附加到视频元素。以前,此操作是通过将 src 属性设置为使用 URL.createObjectURL() 创建的对象网址来完成的,但此方法已废弃

getUserMedia 还可用作 Web Audio API 的输入节点

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

基于 Chromium 的应用和扩展程序也可以集成 getUserMedia。向清单中添加 audioCapture 和/或 videoCapture 权限后,系统会在安装时仅请求和授予一次权限。之后,系统不会再向用户请求授予摄像头或麦克风访问权限。

只需为 getUserMedia() 授予一次权限。首次使用时,浏览器的infobar中会显示一个“允许”按钮。由于 getUserMedia() 被归类为强大功能,Chrome 在 2015 年底弃用了对 getUserMedia() 的 HTTP 访问权限。

其目的可能是为任何流式数据源(而不仅仅是摄像头或麦克风)启用 MediaStream。这样,您就可以从存储的数据或任意数据源(例如传感器或其他输入)进行流式传输。

getUserMedia() 在与其他 JavaScript API 和库结合使用时,才能真正发挥作用:

  • Webcam Toy 是一款照片打印机应用,可使用 WebGL 为照片添加奇妙的效果,这些效果可分享或保存到本地。
  • FaceKat 是一款使用 headtrackr.js 构建的面部跟踪游戏。
  • ASCII 相机使用 Canvas API 生成 ASCII 图片。
由 idevelop.ro/ascii-camera 生成的 ASCII 图片
gUM ASCII 艺术作品!

限制条件

限制条件可用于为 getUserMedia() 设置视频分辨率的值。这还允许支持其他约束条件,例如宽高比;朝向模式(前置摄像头或后置摄像头);帧速率、高度和宽度;以及 applyConstraints() 方法。

如需查看示例,请参阅 WebRTC 示例 getUserMedia:选择分辨率

如果设置了禁止的约束条件值(例如,请求的分辨率不可用),则会返回 DOMExceptionOverconstrainedError。如需实际查看该进程,请参阅 WebRTC 示例 getUserMedia:选择分辨率中的演示。

屏幕和标签页截图

借助 Chrome 应用,您还可以通过 chrome.tabCapturechrome.desktopCapture API 分享单个浏览器标签页或整个桌面的实时视频。(如需查看演示和了解详情,请参阅使用 WebRTC 进行屏幕共享。这篇文章已经有几年的历史了,但仍然很有趣。)

您还可以使用实验性 chromeMediaSource 约束条件,在 Chrome 中将屏幕截图用作 MediaStream 源。请注意,屏幕截图需要使用 HTTPS,并且应仅用于开发目的,因为它是通过命令行标志启用的,如这篇博文中所述。

信号:会话控制、网络和媒体信息

WebRTC 使用 RTCPeerConnection 在浏览器(也称为对等设备)之间传输流式数据,但也需要一种机制来协调通信并发送控制消息,此过程称为信令。WebRTC 指定信令方法和协议。信号传递不属于 RTCPeerConnection API。

相反,WebRTC 应用开发者可以选择他们偏好的任何消息传递协议(例如 SIP 或 XMPP),以及任何适当的双工(双向)通信通道。appr.tc 示例使用 XHR 和 Channel API 作为信号机制。此 Codelab 使用在 Node 服务器上运行的 Socket.io

信号用于交换三种类型的信息:

  • 会话控制消息:用于初始化或关闭通信以及报告错误。
  • 网络配置:计算机的 IP 地址和端口对外界而言是什么?
  • 媒体功能:您的浏览器及其想要与之通信的浏览器可以处理哪些编解码器和分辨率?

必须先通过信号成功交换信息,才能开始点对点流式传输。

例如,假设 Alice 想与 Bob 通信。以下代码段选自 W3C WebRTC 规范,展示了信号传递流程的运作方式。该代码假定在 createSignalingChannel() 方法中创建了某种信号机制。另请注意,在 Chrome 和 Opera 中,RTCPeerConnection 目前带有前缀。

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

首先,Alice 和 Bob 交换网络信息。(“寻找候选对象”这一表达式是指使用 ICE 框架查找网络接口和端口的过程。)

  1. Alice 使用 onicecandidate 处理程序创建 RTCPeerConnection 对象,该处理程序会在候选网络变为可用时运行。
  2. Alice 通过他们正在使用的任何信号通道(例如 WebSocket 或某种其他机制)向 Bob 发送经过序列化的候选数据。
  3. 当 Bob 从 Alice 收到候选消息时,他会调用 addIceCandidate 将候选对象添加到远程对等设备描述中。

WebRTC 客户端(也称为对等设备,在本例中为 Alice 和 Bob)还需要确定和交换本地和远程音频和视频媒体信息,例如分辨率和编解码器功能。发出交换媒体配置信息的信号使用会话描述协议 (SDP) 交换提议回答

  1. Alice 运行 RTCPeerConnection createOffer() 方法。此方法的返回值会传递 RTCSessionDescription - Alice 的本地会话描述。
  2. 在回调中,Alice 使用 setLocalDescription() 设置本地说明,然后通过其信令通道将会话描述发送给 Bob。请注意,只有在调用 setLocalDescription() 之后,RTCPeerConnection 才会开始收集候选对象。这已在 JSEP IETF 草案中编纂。
  3. Bob 使用 setRemoteDescription() 将 Alice 发给他的描述设置为远程描述。
  4. Bob 运行 RTCPeerConnection createAnswer() 方法,并向其传递从 Alice 收到的远程描述,以便生成与她的描述相符的本地会话。系统会向 createAnswer() 回调传递 RTCSessionDescription。Bob 将其设置为本地描述并将其发送给 Alice。
  5. 在 Alice 获取 Bob 的会话描述后,她通过 setRemoteDescription 将其设置为远程描述。
  6. Ping!

RTCSessionDescription 对象是符合会话描述协议 (SDP) 的 Blob。序列化后的 SDP 对象如下所示:

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

可以同时获取和交换网络和媒体信息,但必须先完成这两个过程,才能在对等方之间开始音频和视频流式传输。

前面介绍的 offer/answer 架构称为 JavaScript 会话建立协议 (JSEP)。爱立信的第一个 WebRTC 实现演示视频中有一个非常棒的动画,介绍了信令和流式传输过程。)

JSEP 架构图
JSEP 架构

信号传送流程成功完成后,数据可以直接在调用方和被调用方之间点对点流式传输;如果失败,则可以通过中继服务器(稍后会详细介绍)进行传输。流式传输是 RTCPeerConnection 的工作。

RTCPeerConnection

RTCPeerConnection 是 WebRTC 组件,用于处理点对点之间稳定高效地传输流式数据。

下图显示了 WebRTC 架构,其中展示了 RTCPeerConnection 的作用。您会注意到,绿色部分非常复杂!

WebRTC 架构图
WebRTC 架构(来自 webrtc.org

从 JavaScript 的角度来看,从该图表中要了解的主要内容是,RTCPeerConnection 可保护 Web 开发者免受潜在的各种复杂性的影响。WebRTC 使用的编解码器和协议要完成大量工作,才能实现实时通信,即使在不可靠的网络上也是如此:

  • 丢包隐藏
  • 回声消除
  • 带宽自适应
  • 动态抖动缓冲
  • 自动增益控制
  • 降噪和抑噪
  • Image-cleaning

上文中的 W3C 代码展示了从信号传递角度简化后的 WebRTC 示例。以下是两个可正常运行的 WebRTC 应用的演示。第一个示例是一个简单的示例,用于演示 RTCPeerConnection;第二个示例是一个完全可用的视频聊天客户端。

无服务器的 RTCPeerConnection

以下代码摘自 WebRTC 示例对等连接,其中在一个网页上包含本地 远程 RTCPeerConnection(以及本地和远程视频)。这并不构成任何非常实用的内容,因为调用方和被调用方位于同一页面上,但它确实让 RTCPeerConnection API 的运作方式更加清晰,因为页面上的 RTCPeerConnection 对象可以直接交换数据和消息,而无需使用中介信号机制。

在此示例中,pc1 表示本地对等方(调用方),pc2 表示远程对等方(被调用方)。

来电者

  1. 创建新的 RTCPeerConnection,并从 getUserMedia() 添加数据流: ```js // Servers is an optional configuration file. (请参阅后面的 TURN 和 STUN 讨论。) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. 创建一个优惠,并将其设置为 pc1 的本地说明,以及 pc2 的远程说明。由于调用方和被调用方位于同一页面,因此可以直接在代码中执行此操作,而无需使用信号:js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

被调用方

  1. 创建 pc2,并在添加来自 pc1 的数据流后,在视频元素中显示该数据流:js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API Plus 服务器

在现实世界中,WebRTC 需要服务器,即使是简单的服务器,因此可能会出现以下情况:

  • 用户可以互相发现并交换真实详细信息,例如姓名。
  • WebRTC 客户端应用(对等设备)交换网络信息。
  • 对等设备会交换有关媒体的数据,例如视频格式和分辨率。
  • WebRTC 客户端应用会遍历 NAT 网关和防火墙。

换句话说,WebRTC 需要四种类型的服务器端功能:

  • 用户发现和通信
  • 信令
  • NAT/防火墙穿越
  • 中继服务器(以防点对点通信失败)

NAT 穿透、点对点网络以及构建用于用户发现和信号的服务器应用的要求超出了本文的讨论范围。简而言之,ICE 框架使用 STUN 协议及其扩展 TURN,以便 RTCPeerConnection 能够应对 NAT 穿越和其他网络变化。

ICE 是一种用于连接对等方(例如两个视频聊天客户端)的框架。最初,ICE 会尝试通过 UDP 直接连接对等方,并尽可能缩短延迟时间。在此过程中,STUN 服务器只有一项任务:让 NAT 后面的对等方能够找到其公共地址和端口。(如需详细了解 STUN 和 TURN,请参阅构建 WebRTC 应用所需的后端服务。)

查找关联候选对象
查找连接候选对象

如果 UDP 失败,ICE 会尝试 TCP。如果直接连接失败(尤其是因企业 NAT 穿越和防火墙而导致),ICE 会使用中继 (relay) TURN 服务器。换句话说,ICE 会先使用 STUN 与 UDP 直接连接对等方,如果失败,则回退到 TURN 中继服务器。“寻找候选对象”这一表达式是指查找网络接口和端口的过程。

WebRTC 数据路径
WebRTC 数据路径

WebRTC 工程师 Justin Uberti 在 2013 年 Google I/O WebRTC 演示文稿中详细介绍了 ICE、STUN 和 TURN。(演示文稿的幻灯片提供了 TURN 和 STUN 服务器实现示例。)

一个简单的视频聊天客户端

如需试用 WebRTC(包括使用 STUN 服务器进行信令和 NAT/防火墙穿越),不妨访问 appr.tc 上的视频聊天演示。此应用使用 adapter.js,这是一个 shim,用以使应用不受规范变更和前缀差异的影响。

该代码在日志记录方面故意使用冗长形式。请查看控制台,了解事件的顺序。以下是该代码的详细演示。

网络拓扑

目前实现的 WebRTC 仅支持一对一通信,但可用于更复杂的网络场景,例如多个对等方直接或通过多点控制单元 (MCU) 相互通信,MCU 是一种服务器,可处理大量参与者并执行选择性流转发,以及混合或录制音频和视频。

多点控制单元拓扑图
多点控制单元拓扑示例

许多现有的 WebRTC 应用仅演示了 Web 浏览器之间的通信,但网关服务器可以让在浏览器上运行的 WebRTC 应用与设备(例如电话,也称为 PSTN)以及 VOIP 系统进行交互。2012 年 5 月,Doubango Telecom 开源了使用 WebRTC 和 WebSocket 构建的 sipml5 SIP 客户端,该客户端支持在 iOS 和 Android 上运行的浏览器和应用之间进行视频通话(以及其他潜在用途)。在 Google I/O 大会上,Tethr 和 Tropo 演示了灾难通信框架采用手提箱的形式,使用 OpenBTS 小区,通过 WebRTC 实现功能手机与计算机之间的通信。无运营商的电话通信!

2012 年 Google I/O 大会上的 Tethr/Tropo 演示
Tethr/Tropo:随身携带的灾难通信设备

RTCDataChannel API<

除了音频和视频之外,WebRTC 还支持其他类型数据的实时通信。

RTCDataChannel API 支持点对点交换任意数据,具有低延迟和高吞吐量。如需查看单页面演示并了解如何构建简单的文件传输应用,请分别参阅 WebRTC 示例WebRTC Codelab

该 API 有许多潜在用例,包括:

  • 游戏
  • 远程桌面应用
  • 实时文本聊天
  • 文件传输
  • 分散式网络

该 API 具有多项功能,可充分利用 RTCPeerConnection 并实现强大且灵活的点对点通信:

  • 利用 RTCPeerConnection 会话设置
  • 支持优先级的多个同时使用的渠道
  • 可靠和不可靠传送语义
  • 内置安全 (DTLS) 和拥塞控制
  • 无论是否包含音频或视频,都能使用

我们故意让语法类似于使用 send() 方法和 message 事件的 WebSocket:

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

通信直接在浏览器之间进行,因此即使在使用穿透功能来应对防火墙和 NAT 失败时需要使用中继 (TURN) 服务器,RTCDataChannel 的速度也可能比 WebSocket 快得多。

RTCDataChannel 适用于 Chrome、Safari、Firefox、Opera 和 Samsung Internet。Cube Slam 游戏使用该 API 来传达游戏状态。扮演朋友或扮演熊!创新平台 Sharefest 通过 RTCDataChannel 实现了文件共享,而 peerCDN 则让人们大致了解了 WebRTC 如何实现点对点内容分发。

如需详细了解 RTCDataChannel,请参阅 IETF 的协议规范草稿

安全

实时通信应用或插件可能会通过多种方式破坏安全性。例如:

  • 未加密的媒体或数据可能会在浏览器之间或浏览器与服务器之间被拦截。
  • 应用可能会在用户不知情的情况下录制和分发视频或音频。
  • 恶意软件或病毒可能会与看似无害的插件或应用一起安装。

WebRTC 具有多项功能来避免这些问题:

  • WebRTC 实现使用安全协议,例如 DTLSSRTP
  • 对于所有 WebRTC 组件(包括信令机制)而言,加密是必需的。
  • WebRTC 不是插件。其组件在浏览器沙盒中运行,而不是在单独的进程中运行。组件无需单独安装,并且会在每次更新浏览器时更新。
  • 必须明确授予摄像头和麦克风访问权限,并且当摄像头或麦克风正在运行时,界面会明确显示这一点。

本文不对流媒体的安全性进行完整讨论。如需了解详情,请参阅 IETF 提出的拟议 WebRTC 安全架构

总结

WebRTC 的 API 和标准可以让内容创作和通信工具(包括通话、游戏、视频制作、音乐制作和新闻采集)实现民主化和去中心化。

没有比这更具颠覆性的技术了。

正如博主 Phil Edholm 所的那样,“WebRTC 和 HTML5 或许能够为实时通信带来与原始浏览器为信息带来的相同转变。”

开发者工具

了解详情

标准和协议

WebRTC 支持摘要

MediaStreamgetUserMedia API

  • Chrome 桌面版 18.0.1008 及更高版本;Chrome(Android 版)29 及更高版本
  • Opera 18 及更高版本;适用于 Android 的 Opera 20 及更高版本
  • Opera 12、Opera Mobile 12(基于 Presto 引擎)
  • Firefox 17 及更高版本
  • Microsoft Edge 16 及更高版本
  • iOS 设备上使用 Safari 11.2 及更高版本,MacOS 设备上使用 Safari 11.1 及更高版本
  • Android 版 UC 11.8 及更高版本
  • Samsung Internet 4 及更高版本

RTCPeerConnection API

  • Chrome 桌面版 20 及更高版本;Chrome(Android 版)29 及更高版本(无标志)
  • Opera 18 及更高版本(默认开启);适用于 Android 的 Opera 20 及更高版本(默认开启)
  • Firefox 22 及更高版本(默认处于开启状态)
  • Microsoft Edge 16 及更高版本
  • iOS 设备上使用 Safari 11.2 及更高版本,MacOS 设备上使用 Safari 11.1 及更高版本
  • Samsung Internet 4 及更高版本

RTCDataChannel API

  • Chrome 25 中的实验版,但 Chrome 26 及更高版本中的稳定性更高(并且与 Firefox 具有互操作性);适用于 Android 的 Chrome 29 及更高版本
  • Opera 18 及更高版本中的稳定版(且与 Firefox 互通);适用于 Android 的 Opera 20 及更高版本
  • Firefox 22 及更高版本(默认处于开启状态)

如需详细了解对 getUserMediaRTCPeerConnection 等 API 的跨平台支持,请访问 caniuse.comChrome 平台状态

如需了解适用于 RTCPeerConnection 的原生 API,请参阅 webrtc.org 上的文档