引言
实时通信技术正在迅速改变我们的沟通方式,WebRTC(Web Real-Time Communications)作为这场变革的核心,为开发者和用户带来了无限可能。
《WebRTC探索之旅》系列将分三篇文章带你了解 WebRTC:
第一篇《WebRTC探索:前端视角下的实时通信解析(上)》将介绍 WebRTC 的基础概念和核心功能。 第二篇《WebRTC探索:前端视角下的实时通信解析(中)》将探讨会话流程和信令服务器的搭建。 第三篇《WebRTC探索:前端视角下的实时通信解析(下)》通过实战Demo,展示如何构建音视频通话和即时通讯应用。
让我们一起踏上这场探索之旅,从前端视角深入 WebRTC,开启实时通信的新篇章!
1、什么是WebRTC?
1.1 WebRTC介绍
WebRTC(Web 实时通信)是一个可以用在视频聊天、音频聊天或 P2P 文件分享等 Web 应用中的 API。——摘自:MDN - WebRTC
MDN 对 WebRTC 的定义我们可以拆分为以下三点:
WebRTC 是网页即时通信(Web Real-Time Communication)的缩写; 它提供了支持网页浏览器进行实时语音和视频对话的 API; 允许浏览器之间直接建立连接,实现点对点的通信。
乍一看,我们所熟悉的 WebSocket 好像和 WebRTC 是同一种技术,然而它们之间的差别就像短信和视频通话——虽然都是通信工具,但一个让你“见字如面”,另一个则是“身临其境”。
WebRTC vs WebSocket
为了更好地理解 WebRTC 的独特性,我们先来回顾一下 WebSocket 的主要特点:
WebSocket 是一种基于单个 TCP 连接的全双工通信协议; 它允许服务器主动向客户端推送数据; 在 WebSocket API 中,浏览器和服务器只需完成一次握手,之后就能建立持久性的连接,并进行双向的数据传输。
关键区别:
通信类型:WebSocket 主要用于文本和二进制数据的实时交换,非常适合聊天应用、实时游戏等需要低延迟的数据传输场景。WebRTC 则专注于媒体流的实时传输,如视频和音频通话,具有更复杂的媒体处理能力。 建立连接:WebSocket 连接是建立在 TCP 上的,全双工的、持久的连接。WebRTC 则是点对点的,利用 NAT 穿透 技术(NAT 指的是网络地址转换,Network Address Translation)直接在浏览器之间建立连接,支持多种实时通信场景。 功能支持:WebSocket 不直接支持媒体流的传输和编解码功能,而 WebRTC 内置了对视频、音频流的编解码和传输功能,提供更高层次的实时通信能力。
通过下图,我们可以更直观地比较 WebRTC 和 WebSocket 的区别:
以上对比可以帮助我们更清晰地理解这两种技术的特点。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。
这些 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
参数用于指定音视频设备和其属性。以下是几种常见配置及其应用场景:
同时获取视频和音频输入
const constraints = { audio: true, video: true }
如果没有视频设备,调用时会报错。可以先使用 enumerateDevices
判断是否有视频输入源,再决定是否设置 video
为 false
。
指定设备
const constraints = { audio: { deviceId: audioId }, video: { deviceId: videoId } }
指定分辨率
根据网络带宽和设备能力设置分辨率。例如:
// 高分辨率
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 }
}
指定摄像头方向
使用 facingMode
属性来选择前置或后置摄像头:
// 前置
const constraints = { audio: true, video: { facingMode: "user" } }
// 后置
const constraints = { audio: true, video: { facingMode: { exact: "environment" } } }
指定帧速率 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
基本配置
在屏幕分享中video属性不能设置为false。
const constraints = { video: true };
指定分辨率
const constraints = { video: { width: 1920, height: 1080 } };
音频设置
如果需要分享系统音频,可以将
audio
设置为true
。注意,并非所有浏览器都支持音频分享功能。const constraints = {
audio: true,
video: { width: 1920, height: 1080 }
};示例对比:
有音频:
无音频:当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 的技术细节,你将掌握构建复杂实时通信应用的关键知识。期待在下一篇文章中继续发掘其技术精髓,并学习如何将这些理论应用于实际开发中,实现高效的实时通信解决方案。