pion/webrtc不能单独运行WebRTC服务端,因其仅为客户端实现,缺少信令服务器、NAT穿透协调、房间管理及媒体流路由能力;需自行实现websocket信令通道、显式配置STUN/TURN、隔离PeerConnection实例、正确注册编解码器并开放udp端口。

WebRTC服务端为什么不能只靠 pion/webrtc 自己跑通?
因为 pion/webrtc 是纯客户端级实现,它不内置信令服务器、NAT穿透协调、房间管理或媒体流路由能力。你直接用它写个 main.go 启动,连一个浏览器都连不上——不是代码错,是架构缺环。
常见错误现象:peerConnection.OnICECandidate 一直没触发、浏览器控制台报 ICE connection state is failed、track 没进 OnTrack 回调。
- 必须自己实现信令通道(WebSocket 最常用),把
offer/answer/ice-candidate在客户端和服务端之间中转 -
pion默认不启用 TURN,公网互通基本靠运气;STUN 服务器也得显式配置,否则本地网络测试都可能失败 - 服务端收到
offer后要调用pc.SetRemoteDescription+pc.CreateAnswer,漏掉任一环节,连接就卡死
如何让 pion/webrtc 正确处理多个浏览器客户端?
关键不是“支持多路”,而是避免 PeerConnection 实例之间的状态污染和资源竞争。每个客户端连接必须独占一个 *webrtc.PeerConnection 实例,且生命周期与 WebSocket 连接严格绑定。
使用场景:用户 A 加入房间 / 用户 B 加入 / A 发送 offer 给 B / B 返回 answer —— 整个过程里,A 和 B 的 pc 实例完全隔离。
立即学习“go语言免费学习笔记(深入)”;
- 别复用
*webrtc.Configuration里的SettingEngine或MediaEngine到多个pc,它们不是线程安全的共享对象 - 每个
pc必须有自己的OnICECandidate回调,里面把 candidate 推给对应客户端(不能广播给所有人) - 关闭连接时,必须显式调用
pc.Close(),否则 UDP 端口不释放,net.ListenUDP可能报address already in use
OnTrack 回调没触发?检查这三件事
这是最常被卡住的点:浏览器明明加了 addTrack,服务端却收不到音视频流。根本原因往往不在 WebRTC 协议层,而在 SDP 描述或编码协商上。
参数差异:browser 发出的 offer 可能带 H.264、VP8、AV1 多种 codec,但 pion 默认只注册 VP8 和 Opus;如果浏览器优先选了 H.264,而服务端没注册,就会静默跳过 track。
- 初始化
MediaEngine时,手动添加你需要的 codec:m.RegisterCodec(webrtc.RTPCodecParameters{...}, webrtc.RTPCodecTypeVideo) - 确保浏览器
RTCPeerConnection创建时没禁用 VP8(比如某些企业 chrome 策略会强制 H.264) - 检查 SDP 中
a=recvonly或a=inactive字段——服务端若只做转发,应设为a=sendrecv,否则浏览器不会发流
为什么本地测试通了,一上云服务器就黑屏无声?
本质是 NAT 类型和防火墙策略导致 ICE 候选地址不可达。pion 默认生成的 host candidate(如 192.168.x.x)在公网不可路由,而服务器又没配置 STUN/TURN,结果只能靠 p2p 直连,失败率极高。
性能影响:开启 STUN 后,candidate 数量翻倍,信令消息变大;开启 TURN 后,所有媒体流经中转,延迟增加 50–100ms,带宽成本翻倍。
- 必须配置 STUN:在
webrtc.Configuration的ICEServers里加上{"URLs": ["stun:stun.l.google.com:19302"]}</li> <li>生产环境务必部署私有 TURN(如 <code>coTURN),并把
URLs改成你的turn:your-domain.com:3478?transport=udp - 云服务器安全组要放行 UDP 端口范围(默认
pion用 50000–60000),别只开 WebSocket 的 80/443
真正麻烦的是 ICE 收集顺序和超时控制——SettingEngine.SetICETimeout 设太短,STUN 查询没回来就放弃;设太长,首帧延迟拉满。实际项目里,15 秒是个较稳的折中值。