2、搭建开发环境:浏览器端环境、Node.js信令服务器搭建、本地媒体流获取

好,咱们正式开始动手了。这一章我带你搭好开发环境。你想想看,做音视频开发,最怕什么?最怕环境没配好,代码跑不起来,然后满世界找 bug。我早期踩过不少这种坑,所以今天咱们一步到位。

本章核心目标:让你能在浏览器里调摄像头、麦克风,同时跑起一个 Node.js 信令服务器。说白了,就是让 WebRTC 的“两端”能互相找到对方。

2.1 浏览器端环境准备

WebRTC 是浏览器原生支持的。你不需要装任何插件。我个人习惯用 Chrome 做主力开发,因为它的 DevTools 对 WebRTC 支持最好。Firefox 也可以,但调试体验差一点。

你需要确认三件事:

  • Chrome 版本 ≥ 88(建议用最新稳定版)
  • 开启摄像头和麦克风权限(地址栏左边有个小锁图标)
  • 本地 HTTP 服务(直接用 file:// 协议有时会报权限错误)

小技巧:我习惯在 Chrome 地址栏输入 chrome://webrtc-internals,这里能看到所有 WebRTC 的内部状态。排查问题的时候特别好用。

2.2 Node.js 信令服务器搭建

信令服务器是 WebRTC 的“媒人”。它不传音视频数据,只传一些控制信息,比如“我想和你通话”、“这是我的网络地址”之类的。

我们用 Node.js + WebSocket 来实现。为什么选 WebSocket?因为它双向通信,延迟低,而且浏览器原生支持。

2.2.1 初始化项目

mkdir webrtc-signaling
cd webrtc-signaling
npm init -y
npm install ws

嗯,这里要注意:ws 库是 Node.js 上最流行的 WebSocket 库。我早期用过 socket.io,但后来发现 ws 更轻量,而且和浏览器的原生 WebSocket API 更匹配。

2.2.2 编写信令服务器

创建一个 server.js 文件:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

// 存储所有连接的客户端
const clients = new Map();

wss.on('connection', (ws, req) => {
  const id = Date.now().toString(36);
  clients.set(id, ws);
  console.log(`客户端 ${id} 已连接`);

  // 发送自己的 ID
  ws.send(JSON.stringify({ type: 'id', id }));

  ws.on('message', (message) => {
    const data = JSON.parse(message);
    console.log('收到消息:', data);

    // 转发消息给目标客户端
    if (data.target) {
      const targetWs = clients.get(data.target);
      if (targetWs) {
        targetWs.send(JSON.stringify({
          from: id,
          type: data.type,
          data: data.data
        }));
      }
    }
  });

  ws.on('close', () => {
    clients.delete(id);
    console.log(`客户端 ${id} 已断开`);
  });
});

console.log('信令服务器已启动,端口: 8080');

避坑指南:我曾经在生产环境遇到过一个问题——客户端断开后没有清理 Map,导致内存泄漏。所以一定要在 close 事件里删除对应的条目。

2.2.3 启动服务器

node server.js

看到 信令服务器已启动,端口: 8080 就说明成功了。

2.3 本地媒体流获取

这是 WebRTC 的第一步——拿到摄像头和麦克风的数据。浏览器提供了 navigator.mediaDevices.getUserMedia() 这个 API。

2.3.1 基础用法

async function getLocalStream() {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true
    });

    // 把视频流显示到页面上
    const video = document.getElementById('localVideo');
    video.srcObject = stream;
    video.play();

    console.log('获取本地媒体流成功');
    return stream;
  } catch (err) {
    console.error('获取媒体流失败:', err);
  }
}

getLocalStream();

HTML 部分:

<video id="localVideo" autoplay muted playsinline></video>

注意:muted 属性很重要。如果不加,你可能会听到自己的回声。因为本地视频默认会播放音频,而麦克风又录到了扬声器的声音,就形成了反馈回路。

2.3.2 设置分辨率

你可以指定想要的视频分辨率:

const stream = await navigator.mediaDevices.getUserMedia({
  video: {
    width: { ideal: 1280 },
    height: { ideal: 720 },
    frameRate: { ideal: 30 }
  },
  audio: true
});

这里用 ideal 而不是 exact。为什么?因为浏览器会尽量满足你的要求,但如果摄像头不支持,它会自动降级。用 exact 的话,一旦不匹配就直接报错。我建议你始终用 ideal,除非你有特殊需求。

2.3.3 常见错误处理

错误名称 原因 解决方法
NotAllowedError 用户拒绝了权限 检查浏览器权限设置,或提示用户允许
NotFoundError 没有找到摄像头/麦克风 检查设备是否连接,或使用 enumerateDevices() 列出可用设备
NotReadableError 设备被其他应用占用 关闭其他使用摄像头的程序(如 Zoom、OBS)
OverconstrainedError 指定的约束条件无法满足 改用 ideal 而不是 exact

核心经验:我在做第一个 WebRTC 项目时,花了整整一天排查一个“获取不到视频流”的问题。最后发现是 Chrome 的 HTTPS 限制——getUserMedia 在 HTTP 环境下会被拒绝。所以,请务必用 HTTPS 或 localhost 来测试。

2.4 整体架构图

下面这张图展示了我们搭建的整个环境:浏览器通过 getUserMedia 获取本地媒体流,然后通过 WebSocket 信令服务器交换连接信息,最终建立 P2P 连接。

WebRTC 开发环境架构图 浏览器 A getUserMedia() 本地媒体流 WebSocket 客户端 浏览器 B getUserMedia() 本地媒体流 WebSocket 客户端 Node.js 信令服务器 WebSocket 服务 (端口 8080) 消息转发 / 房间管理 不传输音视频数据 WebSocket 连接 WebSocket 连接 转发 SDP / ICE 转发 SDP / ICE P2P 音视频传输 (SRTP / SCTP) 信令连接 消息转发 P2P 媒体流

2.5 完整测试流程

好,现在我们把所有东西串起来跑一遍:

  1. 启动信令服务器:node server.js
  2. 在浏览器打开你的 HTML 页面(记得用 http://localhost 或 HTTPS)
  3. 允许摄像头和麦克风权限
  4. 打开 DevTools 的 Console,你应该能看到 获取本地媒体流成功
  5. 打开 chrome://webrtc-internals,确认 WebRTC 内部状态正常

调试技巧:如果视频没出来,先检查 Console 有没有报错。如果没有报错但画面黑屏,试试在 getUserMedia 的约束里加上 facingMode: 'user',有些笔记本默认会调用后置摄像头。

嗯,到这里环境就搭好了。你可能会问:“为什么信令服务器这么简单?” 没错,它确实简单。WebRTC 的核心是 P2P 传输,信令只是辅助。后面我们会逐步给它加上房间管理、用户列表等功能。

总结一下:今天我们做了三件事——配好了浏览器环境、搭了一个轻量的 Node.js 信令服务器、用 getUserMedia 拿到了本地媒体流。这三样东西,是后面所有 WebRTC 功能的基础。我建议你多跑几遍,直到闭着眼睛都能搭起来。

公众号:蓝海资料掘金营,微信deep3321