WebRTC 教学工作区 · 课程 0001 · 约 20 分钟 · 前置:无 · 2026-09-24

三大通道:先把 WebRTC 的边界画清

这节课的胜利:用本地服务器打开一个页面,在浏览器里看到自己的摄像头画面, 并说清三件事:WebRTC 管什么、不管什么、以及为什么这个页面必须用 localhost 打开而不是双击 HTML 文件。

为什么是这一步

使命说 WebRTC 是"浏览器之间直连"的标准答案 —— 它把 NAT 穿透、编解码协商、加密传输全包进浏览器。 但很多人一上手就想"两个浏览器连起来",结果被信令、SDP、ICE 一起砸晕。 正确的第一步是只碰最不容易出错的那部分:本地媒体。

最小知识:三条

  1. WebRTC 有三条通道,只有两条归它管。 媒体(音视频)与数据(任意字节)由 WebRTC 提供;而信令(怎么把"我想连你"这句话送到对方) 规范不管 —— 你得自己用 WebSocket/HTTP/甚至手工复制粘贴来实现。
  2. 加密是强制的,不是选项。媒体走 SRTP(密钥由 DTLS 协商),数据通道走 DTLS+SCTP。 你没法配一个"不加密"的 WebRTC —— 这是它和裸 UDP 最大的区别。
  3. 敏感 API 需要"安全上下文"。getUserMedia(拿摄像头/麦克风)只在 https:// 或 http://localhost 下可用。双击本地 HTML 文件打开(file://)在多数浏览器里会被拒 —— 所以我们要起一个本地服务器。

动手:在本机看到自己的摄像头画面

准备一个目录和一个页面文件:

mkdir -p /tmp/webrtc-练习 && cd /tmp/webrtc-练习

新建 media.html(内容如下):

<!doctype html>
<html lang="zh-CN">
<head><meta charset="utf-8"><title>本地媒体</title></head>
<body>
  <h1>本地媒体</h1>
  <video id="v" autoplay playsinline muted style="max-width:480px"></video>
  <p id="s">等待授权…</p>
  <script>
    const v = document.getElementById('v'), s = document.getElementById('s');
    navigator.mediaDevices.getUserMedia({ video: true, audio: false })
      .then(stream => {
        v.srcObject = stream;
        const t = stream.getVideoTracks()[0].getSettings();
        s.textContent = `成功:${t.width}x${t.height} @ ${t.frameRate}fps`;
      })
      .catch(err => { s.textContent = '失败:' + err.name + ' — ' + err.message; });
  </script>
</body>
</html>

起服务器并打开:

cd /tmp/webrtc-练习
python -m http.server 8000
# 然后在浏览器访问:http://localhost:8000/media.html

你会看到两件事之一:

加一道对比实验:把同一个文件用"双击打开"的方式(file://)试一次,看浏览器怎么拒绝你 —— 这一步会让你记住"安全上下文"这件事,而不是背规则。

自测(选项一样长,别从长度上猜)

1. WebRTC 规范不负责哪一部分?

对。信令(怎么把 SDP 与候选送到对方)规范不管 —— 这也是"为什么必须自己搭信令服务器"的答案。其余三项都由 WebRTC 提供。

2. 为什么这个练习页面不能用 file:// 打开?

对。getUserMedia 属于敏感接口,只在安全上下文(https 或 localhost)可用 —— 直接双击打开通常会被拒。注意选项 c 看着也像,但它说的"禁止读取"是结果,不是原因。

3. 看到 NotReadableError 通常意味着?

对。设备被占用(会议软件、录屏工具)是最常见成因;拒绝授权是 NotAllowedError,没有设备是 NotFoundError。认错误名 = 快速定位。