《WebRTC 探索:前端视角下的实时通信解析》(上)

科技   2024-08-30 11:02   福建  

引言

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

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

  • 第一篇《WebRTC探索:前端视角下的实时通信解析(上)》将介绍 WebRTC 的基础概念和核心功能。
  • 第二篇《WebRTC探索:前端视角下的实时通信解析(中)》将探讨会话流程和信令服务器的搭建。
  • 第三篇《WebRTC探索:前端视角下的实时通信解析(下)》通过实战Demo,展示如何构建音视频通话和即时通讯应用。

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

1、什么是WebRTC?

1.1 WebRTC介绍

WebRTCWeb 实时通信)是一个可以用在视频聊天、音频聊天或 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 的默认摄像头和麦克风。然而,在处理复杂场景时,例如选择特定的设备,可以按以下步骤操作:

  1. 列出所有可用的媒体设备:获取设备列表以便选择。
  2. 选择所需的设备:从设备列表中选择适合的摄像头和麦克风。
  3. 配置并传递设备信息:将所选设备的信息传递给浏览器 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 = { audiotruevideotrue }

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

  1. 指定设备
const constraints = { audio: { deviceId: audioId }, video: { deviceId: videoId } }
  1. 指定分辨率

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

// 高分辨率
const constraints = {
    audiotrue,
    video: {
        width: { min320ideal1280max1920 },
        height: { min240ideal720max1080 }
    }
}

// 低分辨率
const constraints = {
    audiotrue,
    video: { width720height480 }
}
  1. 指定摄像头方向

使用 facingMode 属性来选择前置或后置摄像头:

// 前置
const constraints = { audiotruevideo: { facingMode"user" } } 
// 后置
const constraints = { audiotruevideo: { facingMode: { exact"environment" } } }
  1. 指定帧速率 frameRate

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

const constraints = {
    audiotrue,
    video: {
        width1920,
        height1080,
        frameRate: { ideal10max15 }
    }
}

2.2 getDisplayMedia

getDisplayMedia 是什么?

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

如何使用 getDisplayMedia

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

async function getShareMedia({
  const constraints = { video: { width1920height1080 }, audiofalse };
  // 停止之前的媒体流
  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 = { videotrue };
  • 指定分辨率

    const constraints = { video: { width1920height1080 } };
  • 音频设置

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

    const constraints = {
      audiotrue,
      video: { width1920height1080 }
    };

    示例对比:

    • 有音频:

    • 无音频:当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({ videotrueaudiotrue })
    .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 的技术细节,你将掌握构建复杂实时通信应用的关键知识。期待在下一篇文章中继续发掘其技术精髓,并学习如何将这些理论应用于实际开发中,实现高效的实时通信解决方案。

全栈修仙之路
专注分享 TS、Vue3、前端架构和源码解析等技术干货。
 最新文章