Skip to content

工作原理 ​

两端通过一个小型 WebSocket 信令服务器加入同一个房间。服务器只负责中继控制消息:SDP offer 和 answer、ICE candidate 以及 E2EE 密钥。音频、视频和聊天都通过 WebRTC 在两端之间直接传输。Google 的公共 STUN 服务器帮助每一端获取自己的公网地址。

这是默认模式,一个房间容纳两个人。多人通话是一种可选模式,所有人改为连接到一个小型 SFU 服务器。

组成部分 ​

部分技术栈从这里开始读
信令服务器Node.js、wsserver.js
SFU 服务器(可选)Go、Pionsfu-server/
WebVue 3、TypeScript、ViteuseCall.ts
AndroidKotlin、Jetpack Compose、webrtc-sdkPeerConnectionClient.kt
iOSSwift、SwiftUI、webrtc-sdkPeerConnectionClient.swift
macOSSwift、SwiftUI + AppKit,复用 iOS 的通话引擎WebRTCDemoMacApp.swift
WindowsC#、WinUI 3,通过 C shim 调用 libwebrtcCallViewModel.cs
界面
Vue 3, Tailwind CSS, shadcn-vue
WebRTC
浏览器自带的 RTCPeerConnection
信令 socket
WebSocket
摄像头
getUserMedia()
屏幕共享
getDisplayMedia()
切换视频源
RTCRtpSender.replaceTrack()
E2EE
Insertable Streams 或 RTCRtpScriptTransform,在 worker 中运行
背景和贴纸
MediaPipe ImageSegmenter + FaceLandmarker, canvas 2D
画中画
Document Picture-in-Picture API, video PiP fallback
查看这个平台的详细说明 →

每个客户端都遵守的规则 ​

五个相互独立的应用之所以能互相通话,靠的就是下面这几条约定。每一条都有单独的页面详细说明。

  • 已在房间里的一端发起 offer,后加入的一端回复 answer,双方永远不会同时发起 offer。信令
  • 聊天通道在第一个 offer 之前就已创建,所以打开聊天不会触发重新协商。聊天
  • 在摄像头、屏幕和文件之间切换不会重新协商。 视频 sender 保持不变,变的只是给它输送画面的来源。切换视频源
  • 摄像头状态通过消息传递。 被禁用的 track 仍然会发送黑帧,所以每一端都用 media state 告诉对端,并在 track 变化前或后 300 ms 发送。摄像头和麦克风状态
  • E2EE 使用统一的帧格式和统一的密钥选项,开启时 VP8 排在首位。端到端加密
  • 不会自动重连。 信令 socket 一旦关闭,通话就结束。信令

完整的仓库结构,包括每个文件及其作用,见 ARCHITECTURE.md。