WebRTC 的通信架构
- Mesh:多个终端之间两两进行连接。
- MCU(Multipoint Conferencing Unit):各终端将自己要共享的音视频流发送给服务器,服务器端会将在同一个房间中的所有终端的音视频流进行混合,最终生成一个混合后的音视频流再发给各个终端。
- SFU(Selective Forwarding Unit):该方案也是由一个服务器和多个终端组成,不对音视频进行混流,服务器收到某个终端共享的音视频流后,就直接将该音视频流转发给房间内的其他终端。
Peer 的作用
本系统采用 WebRTC 架构为 SFU,当用户要发布媒体流的时候,服务端会创建一个接收器,当用户要订阅媒体流的时候,服务端会创建一个发送器。一个 Peer 记录了一个连接,用来响应发布者或订阅者,并为之创建接收器或发送器。
定义 Peer 结构
type WebRTCPeer struct {
id int
PC *webrtc.PeerConnection
VideoTrack *webrtc.Track
AudioTrack *webrtc.Track
stop chan int
pli chan int
}
PC
表示 WebRTC 连接,它会与实现相应协议的另一个端点建立 p2p 通信。VideoTrack
和AudioTrack
表示视频和音频轨道。stop
是一个管道,当需要停止传输流时,只需要向stop
中发送消息即可。pli
用于关键帧丢包重传。
响应客户端
var engine *WebRTCEngine
func init() {
engine = NewWebRTCEngine()
}
/ AnswerPublisher 响应发布者
func (p *WebRTCPeer) AnswerPublisher(offer webrtc.SessionDescription) (
answer webrtc.SessionDescription, err error) {
return engine.CreateMediaStreamReceiver(offer, &p.PC, &p.VideoTrack, &p.AudioTrack, p.stop, p.pli)
}
// AnswerSubscriber 响应订阅者
func (p *WebRTCPeer) AnswerSubscriber(offer webrtc.SessionDescription,
addVideoTrack, addAudioTrack **webrtc.Track) (answer webrtc.SessionDescription, err error) {
return engine.CreateMediaStreamSender(offer, &p.PC, addVideoTrack, addAudioTrack)
}
发送关键帧
func (p *WebRTCPeer) SendPLI() {
go func() {
defer func() {
if r := recover(); r != nil {
global.Logger.Error(r)
}
}()
ticker := time.NewTicker(time.Second)
i := 0
for {
select {
case <-ticker.C:
p.pli <- 1
if i > 3 {
return
}
i++
case <-p.stop:
return
}
}
}()
}