音视频与实时通信

用生活化的比喻,让你从"只会发文字消息"到"能实现游戏内语音聊天和流媒体"

前置知识:3_1 第14章 游戏实时通信优化(WebSocket 基础)


阅读指南(初学者必看)

为什么你需要学习音视频与实时通信?

越来越多游戏需要实时音视频:

  • MOBA/FPS 的队内语音
  • 社交游戏的视频通话
  • 游戏直播功能
  • 云游戏的视频流

学完本章,你能回答:

  • WebRTC 的核心组件和连接流程是什么?
  • 语音聊天架构有哪几种?怎么选?
  • 音视频编解码的基本原理?
  • 第三方音视频 SDK 怎么选?

本文结构

第一部分:WebRTC 基础
第二部分:实时语音架构
第三部分:音视频编解码
第四部分:第三方服务选型

一、WebRTC 基础

生活类比:WebRTC 就像"可视电话"——浏览器原生支持,不需要装插件就能打电话。

WebRTC 核心组件

1. getUserMedia ── 获取摄像头/麦克风
2. RTCPeerConnection ── P2P 连接
3. RTCDataChannel ── 数据通道

WebRTC 连接流程

1. 信令交换(SDP Offer/Answer)
   A → 服务器 → B:SDP Offer(我的媒体能力)
   B → 服务器 → A:SDP Answer(同意,我的媒体能力)

2. ICE 候选收集
   A 收集自己的网络地址(公网/内网/中继)
   B 收集自己的网络地址
   互相交换

3. P2P 连接建立
   尝试直连(UDP)
   直连失败 → STUN 获取公网 IP
   还失败 → TURN 中继服务器转发

4. 音视频传输
   连接建立后,音视频数据 P2P 传输

WebRTC 代码示例

// 获取本地媒体流
const localStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: false  // 游戏语音不需要视频
});

// 创建 PeerConnection
const pc = new RTCPeerConnection({
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' },  // STUN 服务器
    { urls: 'turn:turn.example.com', username: 'user', credential: 'pass' }  // TURN 服务器
  ]
});

// 添加本地流
localStream.getTracks().forEach(track => pc.addTrack(track, localStream));

// 接收远程流
pc.ontrack = (event) => {
  const remoteAudio = document.getElementById('remoteAudio');
  remoteAudio.srcObject = event.streams[0];
};

// ICE 候选
pc.onicecandidate = (event) => {
  if (event.candidate) {
    // 通过信令服务器发送给对方
    signalingServer.send({ type: 'ice-candidate', candidate: event.candidate });
  }
};

二、实时语音架构

生活类比:语音架构就像"会议系统"——2 人通话直接连,10 人开会需要主持人转发。

三种架构

架构 原理 适合人数 延迟 服务器压力
Mesh 每个人直连所有人 2~4 人 最低
SFU 服务器转发,不解码 5~20 人
MCU 服务器解码混合再编码 20+ 人 较高

Mesh 架构

A ←→ B
↕     ↕
D ←→ C

每个人和其他所有人建立 P2P 连接
N 人需要 N×(N-1)/2 个连接

4 人 = 6 个连接 ✅
10 人 = 45 个连接 ❌(太多)

SFU 架构(推荐)

A → ┐
B → SFU → A/B/C/D
C → ┘
D → ┘

每人发一路流给 SFU
SFU 转发给其他人(不解码,只转发)
服务器压力小,延迟低

游戏推荐:5~20 人的房间语音用 SFU

MCU 架构

A → ┐
B → MCU → 混合流 → A/B/C/D
C → ┘
D → ┘

服务器解码所有人的音频 → 混合 → 重新编码 → 发给每人
每人只收一路流(带宽最省)

缺点:服务器 CPU 开销大,延迟高
适合:大型会议/直播

三、音视频编解码

音频编解码

编解码器 比特率 延迟 适用场景
Opus 6~510 kbps 5~66ms 游戏语音首选 ✅
AAC 64~256 kbps ~100ms 音乐/直播
G.711 64 kbps 传统电话
Speex 2.4~24.6 kbps ~30ms Opus 之前的方案

视频编解码

编解码器 压缩率 延迟 适用场景
H.264/AVC 通用,兼容性最好
H.265/HEVC 高(比H.264省50%) 4K/高画质
VP8/VP9 中/高 WebRTC 默认
AV1 最高 较高 未来标准

游戏语音的特殊处理

1. 降噪(Noise Suppression)
   - 过滤背景噪音
   - WebRTC 内置降噪模块

2. 回声消除(AEC)
   - 消除扬声器播放的声音被麦克风采集
   - 游戏必须开启(不戴耳机时)

3. 自动增益(AGC)
   - 自动调整音量
   - 远近说话声音一样大

4. 静音检测(VAD)
   - 不说话时不发送音频
   - 节省带宽 50%+

四、第三方服务选型

生活类比:自己搭建音视频就像"自己建电话网",用第三方就像"用移动/联通"——后者更稳定更省事。

主流音视频 SDK 对比

声网 Agora 腾讯 TRTC 即构 ZEGO
延迟 < 200ms < 200ms < 200ms
音质
游戏适配 ✅ 有游戏方案 ✅ 有游戏方案 ✅ 有游戏方案
价格
文档 优秀 优秀 优秀
免费额度 每月1万分钟 每月1万分钟 每月1万分钟

选型建议

游戏语音方案选择:

1. 小团队/MVP → 第三方 SDK(声网/腾讯TRTC)
   优势:开发快、稳定、有免费额度
   劣势:有依赖、长期成本高

2. 大团队/自研需求 → 自建 SFU(MediaSoup/LiveKit)
   优势:自主可控、无依赖
   劣势:开发维护成本高

3. 不推荐:纯 WebRTC 自研
   原因:信令服务器、TURN/STUN、NAT 穿透等太复杂

推荐路径:先用第三方 SDK → 量大后自建 SFU

自问自答

Q1:游戏一定要有语音聊天吗?

不一定。休闲游戏不需要。竞技游戏(MOBA/FPS/吃鸡)必须。社交游戏推荐。语音能显著提升团队配合和游戏体验。

Q2:WebRTC 在微信小游戏中能用吗?

微信小游戏支持 wx.createLivePlayerwx.createLivePusher,但不完全支持标准 WebRTC API。需要用微信的实时音视频组件或第三方 SDK 的小游戏版。

Q3:语音聊天会不会影响游戏性能?

影响很小。Opus 编码比特率约 32kbps,现代网络完全无压力。CPU 开销约 2~5%。建议语音和游戏逻辑在不同线程处理。

Q4:自己搭建 SFU 服务器需要什么?

MediaSoup(Node.js)或 LiveKit(Go)是开源 SFU。需要:1. 高带宽服务器(100Mbps+);2. TURN 服务器(NAT 穿透失败时中继);3. 信令服务器(WebSocket)。

Q5:云游戏的视频流和语音有什么区别?

云游戏是"远程桌面"——服务器渲染画面 → 编码视频流 → 传到客户端。延迟要求更低(< 50ms),带宽更大(5~20Mbps)。技术栈不同,但底层都依赖 WebRTC/QUIC。


实践任务

  1. WebRTC 语音 Demo:2 人浏览器语音通话
  2. 接入第三方 SDK:用声网 Agora 实现游戏内语音
  3. 音频处理:实现降噪 + 静音检测 + 音量可视化
  4. 架构设计:为 5 人小队设计语音架构方案
  5. 性能测试:测试语音对游戏 FPS 和网络延迟的影响

与其他章节的关联

本节内容 关联章节 关联点
WebSocket 3_1 第14章 游戏实时通信优化 WebRTC 信令用 WebSocket
网络优化 3_1 第14章 游戏实时通信优化 弱网下的音视频处理
云游戏 5_2 第02章 云游戏与边缘计算 云游戏基于视频流传输
微信小游戏 5_2 第05章 微信小游戏开发 小游戏的音视频 API
容器化 第03章 Kubernetes 编排 SFU 服务器的 K8s 部署

⬅️ 上一章:版本管理与灰度发布 | ➡️ 返回学习路线图