1.2 架构与三大接口


文档摘要

1.2 架构与三大接口 本节摘要:RTCPeerConnection 这个名字自带劝退气质——名字长、方法多、回调连环。但拆开看,WebRTC 的架构异常清晰:上层三个 JavaScript 接口分管「拿媒体、建连接、传数据」,下层浏览器内核把编解码、加密、打洞全部打包。本节给出全册通用的分层地形图,并点明信令通道为何置身架构之外。读完这一节,你就能给任何一段 WebRTC 代码定位它站在架构的哪一层。 学习目标 阅读完本节,你应当能够: 说出三大核心接口各自封装了什么能力、彼此如何传递对象; 画出从 JS API 到媒体引擎、传输层、加密层的浏览器内部分层; 解释信令为什么不在浏览器内核里、它和媒体通道是什么关系; 用不到三十行代码完成一次媒体采集并展示到页面。

1.2 架构与三大接口

本节摘要:RTCPeerConnection 这个名字自带劝退气质——名字长、方法多、回调连环。但拆开看,WebRTC 的架构异常清晰:上层三个 JavaScript 接口分管「拿媒体、建连接、传数据」,下层浏览器内核把编解码、加密、打洞全部打包。本节给出全册通用的分层地形图,并点明信令通道为何置身架构之外。读完这一节,你就能给任何一段 WebRTC 代码定位它站在架构的哪一层。

学习目标

阅读完本节,你应当能够:

  1. 说出三大核心接口各自封装了什么能力、彼此如何传递对象;
  2. 画出从 JS API 到媒体引擎、传输层、加密层的浏览器内部分层;
  3. 解释信令为什么不在浏览器内核里、它和媒体通道是什么关系;
  4. 用不到三十行代码完成一次媒体采集并展示到页面。

一、问题与直觉:接口为什么是三个

很多教程把 WebRTC 讲成「一个 API」,这是后续一切困惑的源头。真实的设计是三个接口、三种数据、三条通道:

  • MediaStream 与 MediaStreamTrack 管「媒体从哪来」:摄像头、麦克风、屏幕,产出一条条轨道(track);
  • RTCPeerConnection 管「媒体怎么送给对方」:协商格式、打洞、加密、发送,是绝对的主角;
  • RTCDataChannel 管「媒体之外怎么传数据」:聊天消息、状态同步、文件分片,复用与媒体相同的加密连接。

三者关系一句话:轨道从采集接口流出,交给连接接口发送;数据通道是连接接口顺手开的另一条车道。 分三个接口而非一个,是因为三种数据的可靠性诉求完全不同——媒体可以容忍丢帧但不能忍受重传延迟,文件传输恰恰相反。接口分开,策略才能分开。

图:WebRTC 分层架构与数据流向

图:WebRTC 分层架构与数据流向

二、核心原理:三层各管一段

从上往下过一遍这张地形图。应用层只有三个接口和你的业务逻辑;内核层是浏览器厂商用 C++ 实现的引擎(Chrome 系基于开源的 libwebrtc),从设备捕获、音频前处理(回声消除、噪声抑制)、视频编解码,到 RTP 打包、拥塞控制、ICE 打洞、DTLS 加密,全部在这层完成;架构外那条虚线框是信令——它只是你自己的 WebSocket 服务,浏览器对它的存在一无所知。

为什么信令不能内建?回看 1.1 节的留白设计:内建信令等于替所有应用指定一个「中央登记处」,与点对点的哲学冲突。所以你会看到 RTCPeerConnection 的构造函数干干净净,不含任何「对方是谁」的参数——对方地址是后来通过信令通道拿到的候选地址,一个一个喂进去的。

信令与媒体的关系,用一个类比:信令是婚礼司仪,媒体是婚后生活。司仪只负责让两家交换信物(SDP)与联系方式(候选地址),办完事就退场;之后两家的日子(媒体数据)自己过,与司仪再无关系——甚至司仪中途倒闭,通话照常进行。

三、工程实践要点:先跑通第一段采集

架构讲再多,不如让摄像头亮起来。下面这段代码是从零开始的第一步,也是第 2 章的预告:

// 最小采集示例:打开摄像头与麦克风并显示在页面上 async function startPreview() { try { // 约束对象:只带基础项,详细参数留给第 2 章 const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true, }); // 把媒体流挂到 video 标签,页面即可看到自己 document.querySelector('video').srcObject = stream; } catch (err) { // 权限拒绝、设备占用、无设备都会走到这里 if (err.name === 'NotAllowedError') { console.log('用户拒绝了摄像头授权'); } else { console.log('采集失败:', err.name); } } }

三个工程细节值得现在就记住。其一,getUserMedia 必须在 HTTPS 或 localhost 环境下才存在,用 http 打开页面会直接报 mediaDevices 为 undefined——大量「代码没错但不工作」的疑问源于此。其二,轨道对象是引用:同一个 track 可以同时给 video 预览和 RTCPeerConnection 发送,浏览器内部自动分流。其三,采集结果不是「一路视频」而是轨道集合,音视频各自独立成轨,这也为后面「只关麦不关摄像头」这类操作留下空间。

第二个小示例,展示三大接口如何咬合——把轨道塞进连接:

// 三大接口的咬合:轨道交给连接,数据通道由连接创建 const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.example.net' }], // 第 4 章展开 }); const stream = await navigator.mediaDevices.getUserMedia({ video: true }); stream.getTracks().forEach((track) => { pc.addTrack(track, stream); // 采集接口的产物 -> 连接接口 }); const dc = pc.createDataChannel('chat'); // 数据通道从连接接口长出

💡 关键直觉:把 RTCPeerConnection 想象成一台「加密传真机」,addTrack 是把文件放进进纸口,信令是你打电话问对方传真号,DTLS 握手是双方核对传真暗号。传真机本身从不管你的电话是怎么打的。

本节要点回顾

  • 三接口三分工:MediaStream 管采集、RTCPeerConnection 管连接与传输、RTCDataChannel 管任意数据,分开是因为可靠性与实时性的策略诉求不同。
  • 内核层承担重活:音频前处理、编解码、RTP 打包、拥塞控制、ICE、DTLS 全部在浏览器内部完成,JS 层只做编排。
  • 信令在架构之外:交换 SDP 与候选地址的通道由应用自建,浏览器不知道也不关心它的存在。
  • HTTPS 是硬前提:非安全上下文里 mediaDevices 直接不存在,排查采集问题先看地址栏。
  • 轨道是流动的通用货币:一次采集,多处消费——预览、发送、录制、替换,都围绕 track 对象进行。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U