WebRTC 使用入门

WebRTC 是长期以来为实现开放且不受限制的网络而进行的战争中的一个新战线。

JavaScript 的发明者 Brendan Eich

无需插件即可进行实时通信

试想一下,如果手机、电视和电脑可以在一个通用平台上通信,会是怎样一番景象。想象一下,如果能轻松地向 Web 应用添加视频聊天和点对点数据共享功能,那该有多好。这正是 WebRTC 的愿景。

想试试吗?Google Chrome、Safari、Firefox 和 Opera 的桌面版和移动版均支持 WebRTC。您可以先从 appr.tc 上的简单视频聊天应用入手:

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

快速入门

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

或者,您也可以直接进入 WebRTC Codelab,这是一份分步指南,其中介绍了如何构建完整的视频聊天应用,包括简单的信令服务器。

WebRTC 简史

对于 Web 而言,最后一个主要挑战之一是实现通过语音和视频进行的人际交流,即实时通信 (RTC)。在 Web 应用中,RTC 应该像在文本输入框中输入文本一样自然。如果没有它,您在创新和开发新的互动方式方面的能力就会受到限制。

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

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

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

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

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(一个由 Google 在 WebRTC 社区的帮助下维护的 JavaScript shim)来抽象化浏览器差异和规范变更。

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() 授予一次权限。首次显示时,浏览器信息栏中会显示“允许”按钮。由于 getUserMedia() 被归类为强大的功能,Chrome 已于 2015 年底弃用对 getUserMedia() 的 HTTP 访问。

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

getUserMedia() 与其他 JavaScript API 和库结合使用时,效果会更好:

  • Webcam Toy 是一款照相亭应用,它使用 WebGL 为照片添加奇特而精彩的效果,这些照片可以分享或保存到本地。
  • FaceKat 是一款使用 headtrackr.js 构建的人脸跟踪游戏。
  • ASCII Camera 使用 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

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

前面介绍的提议/应答架构称为 JavaScript 会话建立协议 (JSEP)。(爱立信的演示视频中有一个精彩的动画,介绍了其首个 WebRTC 实现中的信令和流式传输过程。)

JSEP 架构图
JSEP 架构

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

RTCPeerConnection

RTCPeerConnection 是 WebRTC 组件,用于处理对等方之间稳定高效的流式数据通信。

下图是 WebRTC 架构图,显示了 RTCPeerConnection 的作用。您会发现,绿色部分非常复杂!

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

从 JavaScript 的角度来看,此图表的主要作用是让 RTCPeerConnection 帮助 Web 开发者避开底层隐藏的各种复杂性。WebRTC 使用的编解码器和协议做了大量工作,即使在不可靠的网络上也能实现实时通信:

  • 丢包隐藏
  • 回声消除
  • 带宽自适应性
  • 动态抖动缓冲
  • 自动增益控制
  • 降噪和噪声抑制
  • 图片清理

上述 W3C 代码从信令的角度展示了一个简化的 WebRTC 示例。以下是两个可正常运行的 WebRTC 应用的演练。第一个示例很简单,用于演示 RTCPeerConnection,第二个示例是可全面运行的视频聊天客户端。

无需服务器的 RTCPeerConnection

以下代码取自 WebRTC 示例对等连接,该示例在一个网页上包含本地 远程 RTCPeerConnection(以及本地和远程视频)。这并没有什么实际用途(调用方和被调用方位于同一网页上),但它确实让 RTCPeerConnection API 的运作方式更加清晰,因为网页上的 RTCPeerConnection 对象可以直接交换数据和消息,而无需使用中间信号机制。

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

来电者

  1. 创建新的 RTCPeerConnection 并添加来自 getUserMedia() 的流: ```js // Servers 是一个可选的配置文件。(请参阅下文中有关 TURN 和 STUN 的讨论。) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. 创建 offer 并将其设置为 pc1 的本地描述和 pc2 的远程描述。由于主叫方和被叫方都在同一网页上,因此可以直接在代码中完成此操作,而无需使用信令: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Callee

  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 穿透、对等网络以及构建用于用户发现和信令的服务器应用的要求不在本文的讨论范围之内。简而言之,STUN 协议及其扩展协议 TURNICE 框架用于使 RTCPeerConnection 能够应对 NAT 遍历和其他网络变化。

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

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

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

WebRTC 数据通路
WebRTC 数据通路

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

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

appr.tc 上的视频聊天演示是一个不错的 WebRTC 尝试平台,其中包含使用 STUN 服务器的信令和 NAT/防火墙遍历。此应用使用 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 统计信息,请访问以下网址:
    • Chrome 中的 about://webrtc-internals
    • Opera 中的 opera://webrtc-internals
    • Firefox 中的 about:webrtc
      chrome://webrtc-internals 页面
      chrome://webrtc-internals 屏幕截图
  • 跨浏览器互操作性说明
  • adapter.js 是 Google 在 WebRTC 社区的帮助下维护的 WebRTC JavaScript shim,可抽象出供应商前缀、浏览器差异和规范变更。
  • 如需详细了解 WebRTC 信令流程,请查看控制台中的 appr.tc 日志输出。
  • 如果您觉得这些内容过于复杂,不妨考虑使用 WebRTC 框架,甚至使用完整的 WebRTC 服务
  • 我们始终欢迎您提交错误报告和功能请求:

了解详情

标准和协议

WebRTC 支持摘要

MediaStreamgetUserMedia API

  • Chrome 桌面版 18.0.1008 及更高版本;Chrome for Android 29 及更高版本
  • Opera 18 及更高版本;Opera for Android 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 及更高版本(默认开启);Opera for Android 20 及更高版本(默认开启)
  • Firefox 22 及更高版本(默认处于开启状态)
  • Microsoft Edge 16 及更高版本
  • iOS 设备上的 Safari 11.2 及更高版本,以及 macOS 设备上的 Safari 11.1 及更高版本
  • Samsung Internet 4 及更高版本

RTCDataChannel API

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

如需详细了解 API(例如 getUserMediaRTCPeerConnection)的跨平台支持,请参阅 caniuse.comChrome 平台状态

您还可以访问 webrtc.org 上的文档,了解 RTCPeerConnection 的原生 API。