WebRTC是什么?使用他能做什么?如何实现一个 webRTC 的应用?

WebRTC 是一个开源项目,可在 Web 和本机应用程序中实现音频、视频和数据的实时通信。

WebRTC 代表网络实时通信。它是一个开源免费项目,用于借助 API(应用程序编程接口)为移动应用程序和 Web 浏览器提供实时通信。JavaScript APIHTML5 标签、底层通信协议等由 W3C(万维网联盟)和 IETF(互联网工程任务组)共同定义,以便在未来的 Web 浏览器之间建立一个值得信赖的通信通道。基本上,主要思想是定义 WebRTC API,它允许安全访问设备上的输入外围设备(例如麦克风和网络摄像头),以对等方式与远程设备共享或交换媒体数据、实时数据。

使用场景不仅仅是下面的这些:视频会议、实时视频聊天、与所有朋友分享我们最喜欢的时刻都是 WebRTC 内部存在的一些示例。 你日常使用的所有小工具,如手机、笔记本电脑、智能电视和人工智能等,都连接到互联网。借助 WebRTC ,所有这些设备都可以在一个通用平台上平稳、安全地相互共享语音、视频和实时数据,这也就是 WebRTC 的愿景。WebRTC 是实时通信的未来。

为什么选择 WebRTC?

WebRTC 受欢迎的原因有很多。其中一些原因如下:

  • WebRTC 是一种无插件的现代实时通信技术。它不需要任何额外的插件或应用程序来进行音频、视频流和数据共享。它使用 Javascript 、应用程序编程接口 (API) 和 HTML5 将通信技术嵌入到浏览器中。Google HangoutsWhatsappFacebook MessengerZOOMZendesk 客户支持、Skype for Web 等产品均与 WebRTC 集成。
  • 浏览器能够以点对点的方式直接与其他浏览器交换实时媒体。
  • 比其他各种流媒体系统提供更高级别的安全性,且无需第三方软件。
  • 无需插件即可进行实时通信。

WebRTC 在浏览器中如何工作?

WebRTC 基本上是通过浏览器进行网络实时通信。它允许浏览器之间进行通信。WebRTC Web 应用程序被编程为 HTMLJavaScript 的混合体。用户还可以使用 CSS 来自定义通信的外观。它通过标准化的 WebRTC APIWeb 浏览器工作并通信。因此,WebRTC API 必须提供一系列实用程序。其中一些像连接管理(以点对点方式)、编码/解码功能协商、选择和控制、媒体控制、防火墙等。

WebRTC 的实现范围非常广,因为它是高度可定制的。WebRTC 的功能可以分为三个部分:

  1. MediaStream :第一步是获得用户想要共享的数据。在这种情况下,捕获用户想要的流(音频/视频)、建立的通信模式。本地媒体流允许浏览器访问流设备,例如摄像头、网络麦克风。它还允许浏览器捕获媒体。用户可以利用getUserMedia() 浏览器的功能来获取访问权限。
  2. RTCPeerConnection :一旦用户决定了通信流,下一步就是将其与远程服务的系统连接。它允许我们的浏览器直接与远程服务浏览器(对等点)交换数据以进行语音和视频通话。它允许通过STUNTURN服务器在发送方和接收方之间进行关联。
  3. RTCDataChannel:它允许浏览器双向点对点交换数据。

WebRTC 三角形:

  • WebRTC 包含供 Web 开发人员使用的三个不同的 API 层。
    • 第一层包含 Web 开发人员所需的所有 API,包括 RTCPeerConnectionRTCDataChannel 和媒体流对象及其功能。
    • 第二层是浏览器制造商的 API,比如 safiachromefirefoxedge 等等。
    • 第三个是 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:用户之间的流数据。

第一步:终端创建一个项目

shell 复制代码
❯ mkdir webrtc-web && cd webrtc-web/
❯ pwd
❯ /Users/oo7/Developer/webrtc-web
❯ ~/Developer/webrtc-web 

第二步:从网络摄像头流式传输视频

  • 从网络摄像头获取视频流。
  • 操作流播放。
  • 使用 CSS 和 SVG 来操作视频。

在工作目录中向 index.html 添加一个 video 元素和一个 script 元素:

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>
	<script src="./js/main.js"></script>
</body>
</html>

在 js 文件夹中的 main.js编写一下内容:

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 属性使用该流:

js 复制代码
// 初始化媒体流
navigator.mediaDevices
	.getUserMedia(mediaStreamConstraints)
	.then(gotLocalMediaStream)
	.catch(handleLocalMediaStreamError);

function gotLocalMediaStream(mediaStream) {  
	localVideo.srcObject = mediaStream;
}

constraints 参数允许您指定要获取的媒体。在此示例中,仅视频,因为默认情况下音频处于禁用状态:

js 复制代码
const mediaStreamConstraints = {
	video: true,
};

如果我们对视频如分辨率有要求,使用以下参数来做微调:

js 复制代码
const hdConstraints = {  
	video: {    
		width: {      
			min: 1280    
		},    
		height: {
		   min: 720    
		}
	 }
}

MediaTrackConstraints 规范列出了所有的约束类型,但并不是所有浏览器都支持这些选项。 如果当前选择的相机不支持所请求的分辨率,getUserMedia()则会被拒绝,OverconstrainedError并且不会提示用户授予访问其相机的权限。

如果getUserMedia()执行成功,来自网络摄像头的视频流将被设置为视频元素的源:

js 复制代码
function gotLocalMediaStream(mediaStream) {  
	localVideo.srcObject = mediaStream;
}

ps:

  • video 元素需要增加 autoplay上的属性,如果没有它,我们将只能看到一个边框,或者什么都看不到!

使用 RTCPeerConnection 流式传输视频

什么是 RTCPeerConnection?

RTCPeerConnection 是一个 API ,用于进行 WebRTC 调用以流式传输视频和音频以及交换数据。

我们在同一页面上的两个 RTCPeerConnection 对象(称为对等体)之间建立连接。

添加视频元素和控制按钮

index.html中,将单个视频元素替换为两个视频元素和三个

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

我们直接引用网络的就好了

js 复制代码
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

dapter.js 用于使应用程序免受规范更改和前缀差异的影响。(实际情况中用于WebRTC实现的标准和协议非常稳定,并且只有几个前缀名称。)

改造 index.html, 现在应该如下所示:

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 代码

// 可以github中查看源码

WebRTC 使用 RTCPeerConnection API 建立连接以在 WebRTC 客户端(称为对**等点)**之间传输视频。

在此示例中,两个 RTCPeerConnection 对象位于同一页面上:pc1pc2。没有太多实际用途,但有助于演示 API 的工作原理。

在 WebRTC 对等点之间建立呼叫涉及三个任务:

  • 为呼叫的每一端创建一个 RTCPeerConnection,并在每一端添加来自 的本地流getUserMedia()
  • 获取和共享网络信息:潜在的连接端点称为 ICE 候选端点。
  • 获取并共享本地和远程描述:有关 SDP 格式的本地媒体的元数据。

拍照并通过数据通道分享

  • 拍摄照片并使用 canvas 元素从中获取数据。
  • 与远程用户交换图像数据。

我们通过 RTCDataChannel API 使得共享整个文件成为可能:在此示例中,通过getUserMedia().

该步骤的核心部分如下:

  1. 建立数据通道。请注意,在此步骤中,您不会向对等连接添加任何媒体流。
  2. 使用以下命令捕获用户的网络摄像头视频流getUserMedia()
js 复制代码
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);
  });
}
  1. 当用户单击Snap 按钮时,从视频流中获取快照(视频帧)并将其显示在元素中canvas
js 复制代码
var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');

function snapPhoto() {
  photoContext.drawImage(video, 0, 0, photo.width, photo.height);
  show(photo, sendBtn);
}
  1. 当用户单击**"发送"**按钮时,将图像转换为字节并通过数据通道发送:
js 复制代码
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));
  }
}
  1. 接收端将数据通道消息字节转换回图像并将图像显示给用户:
js 复制代码
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 文件的代码

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 &amp; 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 相关的资料.

参考资料:webrtc.github.io/webrtc-org/...

相关推荐
昨天;明天。今天。3 分钟前
案例-任务清单
前端·javascript·css
zqx_71 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己2 小时前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称2 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色2 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2342 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河3 小时前
CSS总结
前端·css
BigYe程普3 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
余生H3 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍3 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发