WebRTC 是一个开源项目,可在 Web 和本机运用程序中完成音频、视频和数据的实时通讯。
WebRTC 代表网络实时通讯。它是一个开源免费项目,用于凭借 API(运用程序编程接口)为移动运用程序和 Web 浏览器供给实时通讯。JavaScript API、HTML5 标签、底层通讯协议等由 W3C(万维网联盟)和 IETF(互联网工程使命组)共同界说,以便在未来的 Web 浏览器之间树立一个值得信赖的通讯通道。基本上,首要思维是界说 WebRTC API,它答应安全拜访设备上的输入外围设备(例如麦克风和网络摄像头),以对等办法与长途设备同享或沟通媒体数据、实时数据。
运用场景不仅仅是下面的这些:视频会议、实时视频谈天、与一切朋友同享咱们最喜欢的时刻都是 WebRTC 内部存在的一些示例。 你日常运用的一切小工具,如手机、笔记本电脑、智能电视和人工智能等,都衔接到互联网。凭借 WebRTC,一切这些设备都能够在一个通用平台上平稳、安全地彼此同享语音、视频和实时数据,这也就是 WebRTC 的愿景。WebRTC 是实时通讯的未来。
为什么选择 WebRTC?
WebRTC 受欢迎的原因有许多。其间一些原因如下:
- WebRTC 是一种无插件的现代实时通讯技能。它不需求任何额定的插件或运用程序来进行音频、视频流和数据同享。它运用 Javascript、运用程序编程接口 (API) 和 HTML5 将通讯技能嵌入到浏览器中。Google Hangouts、Whatsapp、Facebook Messenger、ZOOM、Zendesk 客户支撑、Skype for Web 等产品均与 WebRTC 集成。
- 浏览器能够以点对点的办法直接与其他浏览器沟通实时媒体。
- 比其他各种流媒体体系供给更高级别的安全性,且无需第三方软件。
- 无需插件即可进行实时通讯。
WebRTC 在浏览器中怎么作业?
WebRTC 基本上是经过浏览器进行网络实时通讯。它答应浏览器之间进行通讯。WebRTC Web 运用程序被编程为 HTML 和 JavaScript 的混合体。用户还能够运用 CSS 来自界说通讯的外观。它经过标准化的 WebRTC API 与 Web 浏览器作业并通讯。因而,WebRTC API 有必要供给一系列实用程序。其间一些像衔接管理(以点对点办法)、编码/解码功能洽谈、选择和操控、媒体操控、防火墙等。
WebRTC 的完成规模十分广,由于它是高度可定制的。WebRTC 的功能能够分为三个部分:
-
MediaStream:第一步是取得用户想要同享的数据。在这种情况下,捕获用户想要的流(音频/视频)、树立的通讯模式。本地媒体流答应浏览器拜访流设备,例如摄像头、网络麦克风。它还答应浏览器捕获媒体。用户能够运用
getUserMedia()
浏览器的功能来获取拜访权限。 - RTCPeerConnection:一旦用户决定了通讯流,下一步就是将其与长途服务的体系衔接。它答应咱们的浏览器直接与长途服务浏览器(对等点)沟通数据以进行语音和视频通话。它答应经过STUN和TURN服务器在发送方和接纳方之间进行关联。
- RTCDataChannel:它答应浏览器双向点对点沟通数据。
WebRTC 三角形:
-
WebRTC 包括供 Web 开发人员运用的三个不同的 API 层。
- 第一层包括 Web 开发人员所需的一切 API,包括 RTCPeerConnection、RTCDataChannel 和媒体流目标及其功能。
- 第二层是浏览器制造商的 API,比方 safia, chrome,firefox,edge 等等。
- 第三个是 Overridable API。
- 假如咱们从客户端-服务器端查看 WebRTC 架构,那么咱们会发现最常用的模型之一是受到 SIP(会话启动协议)梯形的启示。
- 幻想一下咱们和咱们的朋友正在运转 WebRTC 运用程序。我想与咱们的朋友沟通。然后运用信令音讯,其作业是树立和结束通讯。
- 这些音讯经过 HTTP 或 WebSocket 协议传输到 Web 服务器,Web 服务器能够根据需求修改、翻译或管理它们。
- 至于数据途径,PeerConnection 答应媒体直接在浏览器之间活动,无需任何中间服务器。两个网络服务器能够运用标准信令协议进行通讯,而且在咱们和咱们的朋友之间树立通讯。
什么是信号传递?
WebRTC 运用 RTCPeerConnection 在浏览器之间传输流数据,但还需求一种机制来协调通讯和发送操控音讯,该进程称为信令。WebRTC 未指定信令办法和协议。
什么是 STUN 和 TURN?
WebRTC 规划为点对点作业,因而用户能够经过最直接的路由进行衔接。然而,WebRTC 的构建是为了应对实践世界的网络:客户端运用程序需求穿越NAT 网关和防火墙,而且点对点网络需求在直接衔接失利时进行回退。在此进程中,WebRTC API 运用 STUN 服务器获取计算机的 IP 地址,并运用 TURN 服务器作为中继服务器,以防点对点通讯失利。
WebRTC 安全吗?
一切 WebRTC 组件都有必要加密,而且其 JavaScript API
只能从安全来历(HTTPS
或本地主机)运用。信令机制不是由 WebRTC 标准界说的,因而您需求确保运用安全协议。
WebRTC 的局限性:
- 有必要能够拜访快速的互联网衔接才能与 WebRTC 进行通讯。
- 它不供给任何离线服务。
- 它并非在一切浏览器中都可用。
- 没有固定的服务为每个浏览器供给基础。它不断更新,一些软件可能比其他软件供给更复杂的服务,而且具有易于拜访和其他设施。
快速入门
WebRTC 有多个 JavaScript API。
-
getUserMedia()
:捕获音频和视频。 -
MediaRecorder
:录制音频和视频。 -
RTCPeerConnection
:在用户之间传输音频和视频。 -
RTCDataChannel
:用户之间的流数据。
第一步:终端创建一个项目
❯ mkdir webrtc-web && cd webrtc-web/
❯ pwd
❯ /Users/oo7/Developer/webrtc-web
❯ ~/Developer/webrtc-web
第二步:从网络摄像头流式传输视频
- 从网络摄像头获取视频流。
- 操作流播映。
- 运用 CSS 和 SVG 来操作视频。
在作业目录中向 index.html
增加一个video
元素和一个script
元素:
<!DOCTYPE html>
<html>
<head>
<title>与WebRTC的实时通讯</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>与WebRTC的实时通讯</h1>
<video src="" autoplay playsinline></video>
<script src="./js/main.js"></script>
</body>
</html>
在 js 文件夹中的 main.js编写一下内容:
'use strict';
const mediaStreamConstraints = {
video: true,
};
//将放置流的视频元素
const localVideo = document.querySelector("video");
//将在视频中播映本地流。
let localStream;
//经过将MediaStream增加到视频元素来处理
function gotLocalMediaStream(mediaStream) {
localStream = mediaStream;
localVideo.srcObject = mediaStream;
}
//经过将带有过错音讯的记录输出到操控台
function handleLocalMediaStreamError(error) {
console.log("navigator.getUserMedia过错: ", error);
}
// 初始化媒体流
navigator.mediaDevices
.getUserMedia(mediaStreamConstraints)
.then(gotLocalMediaStream)
.catch(handleLocalMediaStreamError);
打开浏览器输入服务地址:http://127.0.0.1:5500/work/
虽然是静态文件但是也需求以服务的形式启动
运作办法
调用getUserMedia()
后,浏览器会恳求用户拜访其相机的权限(假如这是第一次恳求对当时源的相机拜访)。假如成功,则返回 mediaStream,媒体元素能够经过以下srcObject
特点运用该流:
// 初始化媒体流
navigator.mediaDevices
.getUserMedia(mediaStreamConstraints)
.then(gotLocalMediaStream)
.catch(handleLocalMediaStreamError);
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
}
该constraints
参数答应您指定要获取的媒体。在此示例中,仅视频,由于默认情况下音频处于禁用状态:
const mediaStreamConstraints = {
video: true,
};
假如咱们对视频如分辨率有要求,运用以下参数来做微调:
const hdConstraints = {
video: {
width: {
min: 1280
},
height: {
min: 720
}
}
}
MediaTrackConstraints标准列出了一切的约束类型,但并不是一切浏览器都支撑这些选项。
假如当时选择的相机不支撑所恳求的分辨率,getUserMedia()
则会被回绝,OverconstrainedError
而且不会提示用户授予拜访其相机的权限。
假如getUserMedia()
履行成功,来自网络摄像头的视频流将被设置为视频元素的源:
function gotLocalMediaStream(mediaStream) {
localVideo.srcObject = mediaStream;
}
ps:
-
video
元素需求增加autoplay
上的特点,假如没有它,咱们将只能看到一个边框,或者什么都看不到!
运用 RTCPeerConnection 流式传输视频
什么是 RTCPeerConnection?
RTCPeerConnection 是一个 API,用于进行 WebRTC 调用以流式传输视频和音频以及沟通数据。
咱们在同一页面上的两个 RTCPeerConnection 目标(称为对等体)之间树立衔接。
增加视频元素和操控按钮
在 index.html中,将单个视频元素替换为两个视频元素和三个
<video id="localVideo" autoplay playsinline></video>
<video id="remoteVideo" autoplay playsinline></video>
<div>
<button id="startButton">开端</button>
<button id="callButton">拨号</button>
<button id="hangupButton">挂断</button>
</div>
一个视频元素将显现来自 RTCPeerconnection 的流,getUserMedia()
另一个视频元素将显现经过 RTCPeerconnection 流式传输的相同视频。(在实践场景的运用程序中,一个视频元素将显现本地流,另一个视频元素将显现长途流。不然自己跟自己视频那叫一个没意思)
增加适配器 adapter.js
咱们直接引用网络的就好了
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
dapter.js 用于使运用程序免受标准更改和前缀差异的影响。(实践情况中用于WebRTC完成的标准和协议十分稳定,而且只要几个前缀称号。)
改造 index.html, 现在应该如下所示:
<!DOCTYPE html>
<html>
<head>
<title>与WebRTC的实时通讯</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>与WebRTC的实时通讯</h1>
<!-- <video src="" autoplay playsinline></video> -->
<video id="localVideo" autoplay playsinline></video>
<video id="remoteVideo" autoplay playsinline></video>
<div>
<button id="startButton">开端</button>
<button id="callButton">拨号</button>
<button id="hangupButton">挂断</button>
</div>
<script src="./js/main.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
</body>
</html>
编写 RTCPeerConnection 代码
WebRTC 运用 RTCPeerConnection API 树立衔接以在 WebRTC 客户端(称为对**等点)**之间传输视频。
在此示例中,两个 RTCPeerConnection 目标坐落同一页面上:pc1
和pc2
。没有太多实践用途,但有助于演示 API 的作业原理。
在 WebRTC 对等点之间树立呼叫触及三个使命:
- 为呼叫的每一端创建一个 RTCPeerConnection,并在每一端增加来自 的本地流
getUserMedia()
。 - 获取和同享网络信息:潜在的衔接端点称为 ICE 候选端点。
- 获取并同享本地和长途描述:有关 SDP 格局的本地媒体的元数据。
摄影并经过数据通道同享
- 拍摄相片并运用 canvas 元素从中获取数据。
- 与长途用户沟通图画数据。
咱们经过 RTCDataChannel API 使得同享整个文件成为可能:在此示例中,经过getUserMedia()
.
该过程的中心部分如下:
- 树立数据通道。请注意,在此过程中,您不会向对等衔接增加任何媒体流。
- 运用以下命令捕获用户的网络摄像头视频流
getUserMedia()
:
var video = document.getElementById('video');
function grabWebCamVideo() {
console.log('正在获取用户媒体 (video) ...');
navigator.mediaDevices.getUserMedia({
video: true
})
.then(gotStream)
.catch(function(e) {
alert('getUserMedia() error: ' e.name);
});
}
- 当用户单击Snap按钮时,从视频流中获取快照(视频帧)并将其显现在元素中
canvas
:
var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');
function snapPhoto() {
photoContext.drawImage(video, 0, 0, photo.width, photo.height);
show(photo, sendBtn);
}
- 当用户单击**“发送”**按钮时,将图画转换为字节并经过数据通道发送:
function sendPhoto() {
//将数据通道音讯拆分为此字节长度的块。
var CHUNK_LEN = 64000;
var img = photoContext.getImageData(0, 0, photoContextW, photoContextH),
len = img.data.byteLength,
n = len / CHUNK_LEN | 0;
console.log('共发送 ' len ' byte(s)');
dataChannel.send(len);
//拆分相片并以大约64KB的数据块发送
for (var i = 0; i < n; i ) {
var start = i * CHUNK_LEN,
end = (i 1) * CHUNK_LEN;
console.log(start ' - ' (end - 1));
dataChannel.send(img.data.subarray(start, end));
}
//发送提示(假如有)
if (len % CHUNK_LEN) {
console.log('last ' len % CHUNK_LEN ' byte(s)');
dataChannel.send(img.data.subarray(n * CHUNK_LEN));
}
}
- 接纳端将数据通道音讯字节转换回图画并将图画显现给用户:
function receiveDataChromeFactory() {
var buf, count;
return function onmessage(event) {
if (typeof event.data === 'string') {
buf = window.buf = new Uint8ClampedArray(parseInt(event.data));
count = 0;
console.log('Expecting a total of ' buf.byteLength ' bytes');
return;
}
var data = new Uint8ClampedArray(event.data);
buf.set(data, count);
count = data.byteLength;
console.log('count: ' count);
if (count === buf.byteLength) {
//一切数据块都已接纳
console.log('Done. Rendering photo.');
renderPhoto(buf);
}
};
}
function renderPhoto(data) {
var canvas = document.createElement('canvas');
canvas.width = photoContextW;
canvas.height = photoContextH;
canvas.classList.add('incomingPhoto');
// trail是保存传入图画的元素
trail.insertBefore(canvas, trail.firstChild);
var context = canvas.getContext('2d');
var img = context.createImageData(photoContextW, photoContextH);
img.data.set(data);
context.putImageData(img, 0, 0);
}
以下是 index.html 文件的代码
<!DOCTYPE html>
<html>
<head>
<title>与WebRTC的实时通讯</title>
<link rel="stylesheet" href="/css/main.css" />
</head>
<body>
<h1>与WebRTC的实时通讯</h1>
<h2>
<span>Room URL: </span><span id="url">...</span>
</h2>
<div id="videoCanvas">
<video id="camera" autoplay></video>
<canvas id="photo"></canvas>
</div>
<div id="buttons">
<button id="snap">Snap</button><span> then </span><button id="send">Send</button>
<span> or </span>
<button id="snapAndSend">Snap & Send</button>
</div>
<div id="incoming">
<h2>Incoming photos</h2>
<div id="trail"></div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="js/main.js"></script>
</body>
</html>
总结
WebRTC 是实时通讯的未来。日常运用的一切小工具,如手机、笔记本电脑、智能电视和人工智能等,都衔接到互联网。凭借 WebRTC,一切这些设备都能够在一个通用平台上平稳、安全地彼此同享语音、视频和实时数据,这也就是 WebRTC 的愿景。
WebRTC 相关的 API 许多,假如想要构建好一个 webRTC 的运用程序需求参阅 webRTC 相关的资料.