我基于PeerJS搭建了一个P2P视频软件
一个拖了很久的待办
“玩一玩WebRTC” 在我的待办清单里躺了大概一年,因为这事有趣,但是项目太多无法抽身,最近vibe coding大行其道,这种小demo的项目,可以快速实现,大概花了2天时间实现了这个旧项目:Peertest
WebRTC、PeerJS、视频通话的关系
在聊实现之前,先理清这几个概念的关系。
WebRTC:底层的通信协议
WebRTC (Web Real-Time Communication) 是浏览器原生的实时通信 API。它可以让两个浏览器直接传输音视频数据。
WebRTC 只负责"传输",不负责"建立连接"。
打个比方,WebRTC 就像是两个人打电话的”通话线路”,但在此之前,你们得先交换电话号码。这个”交换号码”的过程,叫信令(Signaling)。
信令服务器:连接的桥梁
两个浏览器要建立 WebRTC 连接,需要先交换一些信息:
- 谁是发起方、谁是接收方
- 各自支持什么编码格式
- 如何穿透 NAT(IP 地址和端口)
这些信息需要通过一个中间服务器来传递,这就是信令服务器。
而这就是 PeerJS 存在的意义。
它帮你:
- 处理好了信令握手
- 封装了复杂的 WebRTC API
- 提供了现成的 PeerServer
- 用简单的
peer.call()就能发起通话
原本需要几百行代码的 WebRTC 连接,用 PeerJS 几行就能搞定。
所以关系是这样的:
1 | 视频通话应用 |
我的选型
前端:React + TypeScript + Vite
选择 React 是因为熟悉,TypeScript 是为了类型安全,Vite 则是因为开发体验好(真的很快)。
整个应用只有一个 App.tsx 组件,单组件架构。我觉得这个规模的项目,没必要过度设计。
核心设计:主叫方(房间建立者)和被叫方(加入房间这)
建立房间模式
1 | 用户点击"建立房间" |
加入房间模式
1 | 用户粘贴分享链接,点击"呼叫" |
单组件的状态管理
没有用 Redux、Zustand 任何状态库,纯 React hooks:
1 | const [mode, setMode] = useState<'join' | 'create'>('join') |
我觉得这就是”刚刚好”的复杂度——再多就是过度设计。
服务器架构
两个独立的服务:
- PeerServer (peer-server.js):Node.js 写的信令服务器,端口 9009
- Vite Dev Server:前端开发服务器
配置 host: '0.0.0.0' 是为了支持局域网访问——这样我的手机可以和电脑互相通话。
一个小细节:6 位数字房间号
我用了随机生成 6 位数字作为房间 ID:
1 | const generateRoomId = (): string => { |
为什么不用 UUID?因为数字好记、好输入,特别是手机端粘贴链接时体验更好。
摄像头控制
每个视频框都有独立的开关:
- 本地摄像头:真实开启/关闭 MediaStream
- 远程显示:只切换可见度(opacity 0.3-1.0)
本地视频加了镜像翻转 transform: scaleX(-1),不然看着自己的视频会很别扭。
技术栈总结
| 层级 | 技术 |
|---|---|
| 前端框架 | React 19 + TypeScript |
| 构建工具 | Vite |
| WebRTC 封装 | PeerJS 1.5.5 |
| 信令服务器 | PeerServer (peer 包) |
| 状态管理 | React hooks |
再见
写到这里,代码已经能跑了。两个浏览器窗口可以互相通话,画质清晰,延迟低。
这个项目不大,但填补了我对 WebRTC 的认知空白。
对了,代码在 Gitee,欢迎 star。
再见,下一个待办见。
我基于PeerJS搭建了一个P2P视频软件