专栏名称: 前端早读课
我们关注前端,产品体验设计,更关注前端同行的成长。 每天清晨五点早读,四万+同行相伴成长。
目录
相关文章推荐
前端早读课  ·  【第3377期】剪贴板如何存储不同类型的数据 ·  昨天  
前端早读课  ·  【招聘】北京Dine团队招聘前端工程师 ·  5 天前  
前端大全  ·  2024 年 12 个最佳 ... ·  1 周前  
前端大全  ·  写给懒人的Vue3快速查阅宝典 ·  1 周前  
前端早读课  ·  【第3375期】WebRTC ... ·  6 天前  
51好读  ›  专栏  ›  前端早读课

【第3375期】WebRTC 探索:前端视角下的实时通信解析(上)

前端早读课  · 公众号  · 前端  · 2024-09-13 08:00

正文

前言

主要介绍了 WebRTC 技术的基础知识、浏览器兼容性、适用场景以及常用 API,并预览了接下来的探讨内容。今日前端早读课文章由 @苏璇分享,公号:大转转 FE 授权。

正文从这开始~~

引言

实时通信技术正在迅速改变我们的沟通方式,WebRTC(Web Real-Time Communications)作为这场变革的核心,为开发者和用户带来了无限可能。

《WebRTC 探索之旅》系列将分三篇文章带你了解 WebRTC:

  • 第一篇《WebRTC 探索:前端视角下的实时通信解析(上)》将介绍 WebRTC 的基础概念和核心功能。

  • 第二篇《WebRTC 探索:前端视角下的实时通信解析(中)》将探讨会话流程和信令服务器的搭建。

  • 第三篇《WebRTC 探索:前端视角下的实时通信解析(下)》通过实战 Demo,展示如何构建音视频通话和即时通讯应用。

让我们一起踏上这场探索之旅,从前端视角深入 WebRTC,开启实时通信的新篇章!

【早阅】Mediasoup:一个开源的流媒体工具

1、什么是 WebRTC?

1.1 WebRTC 介绍

WebRTC(Web 实时通信)是一个可以用在视频聊天、音频聊天或 P2P 文件分享等 Web 应用中的 API。—— 摘自:MDN - WebRTC

MDN 对 WebRTC 的定义我们可以拆分为以下三点:

  • WebRTC 是网页即时通信(Web Real-Time Communication)的缩写;

  • 它提供了支持网页浏览器进行实时语音和视频对话的 API;

  • 允许浏览器之间直接建立连接,实现点对点的通信。

乍一看,我们所熟悉的 WebSocket 好像和 WebRTC 是同一种技术,然而它们之间的差别就像短信和视频通话 —— 虽然都是通信工具,但一个让你 “见字如面”,另一个则是 “身临其境”。

【第1882期】基于Unix Socket的可靠Node.js HTTP代理实现(支持WebSocket协议)

WebRTC vs WebSocket

为了更好地理解 WebRTC 的独特性,我们先来回顾一下 WebSocket 的主要特点:

  • WebSocket 是一种基于单个 TCP 连接的全双工通信协议;

  • 它允许服务器主动向客户端推送数据;

  • 在 WebSocket API 中,浏览器和服务器只需完成一次握手,之后就能建立持久性的连接,并进行双向的数据传输。

关键区别:

  • 通信类型:WebSocket 主要用于文本和二进制数据的实时交换,非常适合聊天应用、实时游戏等需要低延迟的数据传输场景。WebRTC 则专注于媒体流的实时传输,如视频和音频通话,具有更复杂的媒体处理能力。

  • 建立连接:WebSocket 连接是建立在 TCP 上的,全双工的、持久的连接。WebRTC 则是点对点的,利用 NAT 穿透 技术(NAT 指的是网络地址转换,Network Address Translation)直接在浏览器之间建立连接,支持多种实时通信场景。

  • 功能支持:WebSocket 不直接支持媒体流的传输和编解码功能,而 WebRTC 内置了对视频、音频流的编解码和传输功能,提供更高层次的实时通信能力。

通过下图,我们可以更直观地比较 WebRTC 和 WebSocket 的区别:

【第3260期】WebSockets、服务器推送事件、Long-Polling、WebRTC、WebTransport对比

以上对比可以帮助我们更清晰地理解这两种技术的特点。WebRTC 和 WebSocket 各自有不同的优势,可以说 WebRTC 目前是将前端技术和音视频嫁接起来最佳的媒介。

1.2 WebRTC 的浏览器兼容性

WebRTC 在主流浏览器中的支持情况如下图所示,这些信息来自 caniuse.com 网站,提供了各个浏览器对 WebRTC 的兼容性概况:

兼容性注意事项:

  • 移动端支持:大多数移动浏览器也支持 WebRTC。需要注意的是,在 iOS 设备上,Safari 浏览器的版本需大于 10.1。

  • 旧版浏览器:一些老旧的浏览器或 WebView 组件可能不支持 WebRTC,建议在发布应用前进行全面的兼容性测试。

  • 网络环境与隐私权限:不同浏览器对摄像头、麦克风等隐私权限的处理方式有所不同,用户授权和连接稳定性可能受此影响。

通过查看上图中的兼容性数据,我们可以更好地评估 WebRTC 在不同平台上的表现,优化应用以适配各种浏览器环境。

1.3 WebRTC 适用场景
  • 在线教育:如新东方云教室、智慧树、猿辅导、网易云课堂,通过 WebRTC 实现实时互动教学。

  • 社交媒体:增强用户互动体验,如 Soul 和 陌陌 的视频聊天功能等。

  • 视频会议:如腾讯会议、钉钉,提供高质量的实时视频会议体验。

  • 直播平台:如抖音、快手,利用 WebRTC 技术进行低延迟的实时直播。

  • 物联网(IoT):提供了低延迟的音视频通信能力,可以用于物联网设备之间的实时视频监控,如小米智能家居、小天才等。

1.4 WebRTC 的优缺点

WebRTC 的出现标志着实时通信技术的一次重要革新。作为一种开源标准,WebRTC 使得浏览器能够直接进行音视频通信,无需额外插件或第三方软件。它结合了前端技术与实时多媒体通信,为开发者和用户提供了新的可能性。然而,尽管 WebRTC 拥有众多优点,它也面临一些挑战。下面我们来详细探讨 WebRTC 的主要优缺点:

优点

  • 实时通信:WebRTC 支持浏览器之间的实时音频、视频和数据通信,无需任何插件或第三方软件。

  • 高质量的音视频通信: WebRTC 使用最先进的音频和视频编解码器,如 Opus 和 VP8/VP9/H.264,可以提供高质量的通信体验。

  • 端到端加密:WebRTC 的所有通信都是端到端加密的,保护了用户的隐私和数据安全。

  • P2P 连接:WebRTC 支持直接的 P2P 连接,可以减少延迟和带宽消耗,提高通信效率。

  • 跨平台和跨浏览器:WebRTC 是一个开源的标准,被大多数现代浏览器和平台支持。

缺点

  • 复杂的信令过程:WebRTC 本身并不包含信令协议,开发者需要自己实现信令过程,增加了开发的复杂性。(信令是指在 WebRTC 会话建立过程中,用于在通信双方之间交换必要的控制信息的机制)

  • 防火墙和 NAT 问题 :在某些网络环境下,建立 P2P 连接可能会受到防火墙和 NAT 的限制。

  • 隐私问题:虽然 WebRTC 的通信是加密的,但仍有可能泄露用户的 IP 地址,可能会引发一些隐私问题。

  • 资源消耗:实时音视频通信需要消耗大量的 CPU 和带宽资源,可能会影响设备的性能。

2、web 端基础常用相关 API

WebRTC 提供了一些 API,用于实现 Web 端的音视频通信。作为 W3C 标准,它涉及到用户的隐私设备如摄像头和麦克风。接下来,我们将简要介绍这些常用的 WebRTC API。

【第2383期】JavaScript是如何工作的:WebRTC 及点对点网络通信机制

这些 API 为实现实时通信提供了强大的支持,每个 API 都各有其独特的用途。首先,我们来看看如何通过 WebRTC 访问用户的音视频设备。

2.1 getUserMedia

getUserMedia 是什么?

getUserMedia 是 WebRTC API 中用于访问用户音视频设备的接口,包括摄像头和麦克风。无论是通过 USB 连接的设备还是虚拟设备,都可以通过这个 API 进行访问。

如何使用 getUserMedia?

在简单场景下,直接调用 getUserMedia 的默认参数即可获取 PC 的默认摄像头和麦克风。然而,在处理复杂场景时,例如选择特定的设备,可以按以下步骤操作:

  • 列出所有可用的媒体设备:获取设备列表以便选择。

  • 选择所需的设备:从设备列表中选择适合的摄像头和麦克风。

  • 配置并传递设备信息:将所选设备的信息传递给浏览器 API 以进行设置。

 // 1. 列出所有可用的媒体设备
navigator.mediaDevices.enumerateDevices()
.then(devices => {
devices.forEach(device => {
console.log(device.kind, device.label, device.deviceId);
});

// 2. 根据用户选择的 deviceId 请求媒体流
const constraints = {
audio: { deviceId: { exact: selectedAudioDeviceId } },
video: { deviceId: { exact: selectedVideoDeviceId } }
};

// 3. 请求用户媒体流
return navigator.mediaDevices.getUserMedia(constraints);
})
.then(stream => {
// 将媒体流绑定到视频或音频元素上
const videoElement.srcObject = stream;
})
.catch(error => {
console.error('媒体设备访问失败:', error);
});

媒体约束 constraints

在上述代码片段中,constraints 参数用于指定音视频设备和其属性。以下是几种常见配置及其应用场景:

1、同时获取视频和音频输入

 const constraints = { audio: true, video: true }

如果没有视频设备,调用时会报错。可以先使用 enumerateDevices 判断是否有视频输入源,再决定是否设置 video 为 false。

2、指定设备

 const constraints = { audio: { deviceId: audioId }, video: { deviceId: videoId }

3、指定分辨率

根据网络带宽和设备能力设置分辨率。例如:

 // 高分辨率
const constraints = {
audio: true,
video: {
width: { min: 320, ideal: 1280, max: 1920 },
height: { min: 240, ideal: 720, max: 1080 }
}
}

// 低分辨率
const constraints = {
audio: true,
video: { width: 720, height: 480 }
}

4、指定摄像头方向
使用 facingMode 属性来选择前置或后置摄像头:

 // 前置
const constraints = { audio: true, video: { facingMode: "user" } }
// 后置
const constraints = { audio: true, video: { facingMode: { exact: "environment" } } }

5、指定帧速率 frameRate

帧速率影响视频的流畅度。可以根据网络条件调整帧速率:

 const constraints = {
audio: true,
video: {
width: 1920,
height: 1080,
frameRate: { ideal: 10, max: 15 }
}
}
2.2 getDisplayMedia

getDisplayMedia 是什么?

getDisplayMedia API 用于在浏览器中实现屏幕分享功能。它允许用户选择并分享整个屏幕或特定应用窗口,适用于远程会议和在线演示等场景。

如何使用 getDisplayMedia?

调用 getDisplayMedia 获取屏幕分享的媒体流。此 API 返回一个 Promise,解析值为包含屏幕视频流的 MediaStream 对象。

 async function getShareMedia() {
const constraints = { video: { width: 1920, height: 1080 }, audio: false };
// 停止之前的媒体流
if (window.stream) {
window.stream.getTracks().forEach(track => track.stop());
}
try {
return await navigator.mediaDevices.getDisplayMedia(constraints);
} catch (error) {
console.error('屏幕分享失败:', error);
}
}

媒体约束 Constraints

1、基本配置

在屏幕分享中 video 属性不能设置为 false。

 const constraints = { video: true };

2、指定分辨率

 const constraints = { video: { width: 1920, height: 1080 } };

3、音频设置

如果需要分享系统音频,可以将 audio 设置为 true。注意,并非所有浏览器都支持音频分享功能。

 const constraints = {
audio: true,
video: { width: 1920, height: 1080 }
};

示例对比:

1、有音频:

2、无音频:当 audio 设置为 false 后,底部就少了开启系统音频的按钮。

小提示:

在获取新的媒体流之前,建议停止之前的媒体流,以避免设备使用提示,并确保应用逻辑清晰。

 if (window.stream) {
window.stream.getTracks().forEach(track => track.stop());
}
2.3 RTCPeerConnection

RTCPeerConnection 是什么?

RTCPeerConnection 用于管理音视频连接。它帮助你建立和维护与其他用户的实时通信,处理媒体流、网络连接等问题。

如何使用 RTCPeerConnection?

创建 RTCPeerConnection 需要提供一个配置对象,通常包含用于网络穿透的服务器信息(如 STUN 服务器)。

 const configuration = {
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
};
const peerConnection = new RTCPeerConnection(configuration);

主要功能:

1、创建连接请求

  • createOffer (): 发起连接请求。

  • createAnswer (): 响应连接请求。

 peerConnection.createOffer()
.then(offer => peerConnection.setLocalDescription(offer))
.then(() => {
// 发送 offer 给对端
});

2、设置描述信息

  • setLocalDescription (description): 设置本地的连接信息。

  • setRemoteDescription (description): 设置对端的连接信息。

 peerConnection.setRemoteDescription(new RTCSessionDescription(remoteOffer))
.then(() => peerConnection.createAnswer())
.then(answer => peerConnection.setLocalDescription(answer));

3、处理媒体流

  • addTrack (track, stream): 添加音视频轨道到连接中。

  • addIceCandidate (candidate): 添加网络候选地址。

 navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
});

peerConnection.addIceCandidate(new RTCIceCandidate(candidate));

4、事件处理

  • onicecandidate: 当新的网络候选地址出现时触发。

  • ontrack: 当接收到对端的媒体流时触发。

  • oniceconnectionstatechange: 当连接状态变化时触发。

 peerConnection.onicecandidate = (event) => {
if (event.candidate) {
// 发送候选地址到信令服务器
}
};

peerConnection.ontrack = (event) => {
const remoteStream = event.streams[0];
// 显示远程媒体流
videoElement.srcObject = remoteStream;
};
2.4 RTCDataChannel

RTCDataChannel 是什么?

RTCDataChannel 是 WebRTC 提供的一个 API,用于在对等端之间传输任意数据。它支持低延迟、可靠性可选的数据传输方式,使得在音视频通信之外,还可以传输文本、文件等数据。

如何使用 RTCDataChannel?

通过 RTCPeerConnection 创建一个数据通道,并定义其配置。

 const dataChannel = peerConnection.createDataChannel("myDataChannel");

主要功能:

1、发送和接收数据

  • send (data): 通过数据通道发送数据,可以是字符串、二进制数据等。

  • onmessage: 当接收到数据时触发。

 dataChannel.send("Hello, WebRTC!");
dataChannel.onmessage = (event) => {
console.log("Received message:", event.data);
};

2、事件处理

  • onopen: 当数据通道打开时触发。

  • onclose: 当数据通道关闭时触发。

 dataChannel.onopen = () => {
console.log("Data channel is open");
};

dataChannel.onclose = () => {
console.log("Data channel is closed");
};
2.5 API 协同工作

通过 getUserMedia 获取用户的摄像头和麦克风流,结合 getDisplayMedia 进行屏幕分享,再利用 RTCPeerConnection 管理音视频连接,最终通过 RTCDataChannel 实现数据传输。通过这些 API 的协同工作,我们可以轻松实现一个功能齐全的视频通话应用。

3、小结

在《WebRTC 探索之旅:前端视角下的实时通信解析(上)》中,我们迈出了了解 WebRTC 的第一步。我们探讨了 WebRTC 的核心定义及其在开放网络中实现实时音视频交流的能力,同时掌握了基础 API,为构建实时通信应用奠定了基础。

接下来,我们将深入挖掘 WebRTC 的核心技术,包括:

  • 链接方式的多样性:研究 WebRTC 支持的各种连接方式及其影响。

  • PeerConnection 的核心作用:解析 PeerConnection 对象的功能和重要性。

  • 会话流程的梳理:系统化了解 WebRTC 会话的生命周期,包括信令处理和媒体协商。

  • 信令服务器的实践:探讨如何搭建和配置信令服务器以支持 WebRTC 通信。

随着我们进一步探索 WebRTC 的技术细节,你将掌握构建复杂实时通信应用的关键知识。期待在下一篇文章中继续发掘其技术精髓,并学习如何将这些理论应用于实际开发中,实现高效的实时通信解决方案。

关于本文
作者:@苏璇
原文:https://mp.weixin.qq.com/s/SD5fzJ_cdXfMYCJGgLUDpw

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。