Skip to content

完整 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 构建自己的应用:

  1. 替换信令传输:把 WebSocket 改成 Socket.IO 或 HTTP 长轮询,只需修改 SignalChannel 实现
  2. 添加 DataChannel:在 WetRTCConfig.dataChannels 中配置,即可使用消息和文件传输
  3. 屏幕分享:把 getUserMedia 替换为 rtc.media.getDisplayMedia()
  4. 多人群组:扩展信令服务器支持多房间和多人转发

Released under the MIT License.