完整 Demo
一个可直接运行的端到端 WebRTC 音视频通话示例,包含信令服务器和前端页面。
快速启动
bash
# 1. 进入 demo 目录
cd examples/simple-demo
# 2. 安装依赖(仅首次)
pnpm install
# 3. 启动
pnpm start
# 4. 浏览器打开 http://localhost:3456
# 打开两个标签页 —— 一个点「发起连接」,另一个点「加入连接」效果预览
打开后你会看到:
- 两个视频窗口(本地 + 远端)
- 连接状态实时显示(idle → signaling → connecting → connected)
- RTT、丢包率、分辨率等实时统计
- 完整的操作日志面板
文件结构
simple-demo/
├── package.json # 依赖配置
├── server/
│ └── index.js # 信令中继服务器
│ • WebSocket 信令转发
│ • HTTP 静态文件托管
│ • 房间管理(每房间最多 2 人)
└── public/
└── index.html # 前端页面(纯 HTML + ES Module)
• SignalChannel 接口实现
• 摄像头/麦克风采集
• 状态机可视化
• 实时统计展示架构
┌─────────────────┐ ┌─────────────────┐
│ 浏览器标签页 A │ │ 浏览器标签页 B │
│ │ │ │
│ WetRTC │ │ WetRTC │
│ SignalChannel │ ←── WebSocket ───→ │ SignalChannel │
│ MediaManager │ 信令中继 │ MediaManager │
│ StatsMonitor │ │ StatsMonitor │
└────────┬────────┘ └────────┬────────┘
│ │
└──────── P2P (WebRTC) ────────────────┘
音视频流 + DataChannel信令流程
发起方(标签页A) 信令服务器 加入方(标签页B)
│ │ │
│── connect() ─────────│ │
│ │ │
│── offer ────────────→│── offer ──────────→│
│ │ │── createAnswer()
│ │ │
│←── answer ──────────│←── answer ────────│
│ │ │
│── ICE candidate ────→│── ICE candidate ──→│
│←── ICE candidate ───│←── ICE candidate ──│
│ │ │
│◄═══════ P2P 直连 ═══════════════════════►│信令服务器核心逻辑
js
/**
* 信令中继 — 节选(完整源码见 examples/simple-demo/server/index.js)
*/
import { WebSocketServer, WebSocket } from 'ws'
import { createServer } from 'http'
import { readFileSync, existsSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const PORT = 3456
const httpServer = createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*')
// ... SSE 与静态文件托管 ...
})
const wss = new WebSocketServer({ server: httpServer })
const rooms = new Map<string, WebSocket[]>()
wss.on('connection', (ws, req) => {
const url = new URL(req.url || '/', `http://${req.headers.host}`)
const roomId = url.searchParams.get('room') || 'default'
const peers = rooms.get(roomId) ?? []
if (peers.length >= 2) {
ws.send(JSON.stringify({ type: 'error', message: '房间已满' }))
ws.close()
return
}
peers.push(ws)
rooms.set(roomId, peers)
// 转发房间内其他 peer 的消息
ws.on('message', (raw) => {
for (const peer of peers) {
if (peer !== ws && peer.readyState === WebSocket.OPEN) {
peer.send(raw.toString())
}
}
})
})
httpServer.listen(PORT, () => {
console.log(`WetRTC Demo: http://localhost:${PORT}`)
})自定义
你可以参考此 Demo 构建自己的应用:
- 替换信令传输:把 WebSocket 改成 Socket.IO 或 HTTP 长轮询,只需修改
SignalChannel实现 - 添加 DataChannel:在
WetRTCConfig.dataChannels中配置,即可使用消息和文件传输 - 屏幕分享:把
getUserMedia替换为rtc.media.getDisplayMedia() - 多人群组:扩展信令服务器支持多房间和多人转发