interceptor寻踪:pion/interceptor在pion/webrtc里的用法解析
# 初始化:NewPeerConnection
本节主要讲解WebRTC标准接口NewPeerConnection内部和调用前所需要进行的interceptor初始化操作。在开始前,你首先需要去《用实例学习pion - rtp-forwarder》和《pion学习总结:等待传入track的一般流程》里看看NewPeerConnection的用法以及在调用NewPeerConnection前所需要进行的操作;然后你还需要理解《pion/interceptor浅析》中关于级联的思想和《用实例学习pion interceptor - nack》里出现的interceptor.NewChain是什么。
# 在NewPeerConnection之前
从《用实例学习pion - rtp-forwarder》中可以看到,在正式调用api.NewPeerConnection之前,与pion/interceptor有关的操作主要就是创建interceptor.Registry并调用webrtc.NewAPI创建WebRTC标准API。这个interceptor.Registry非常之简单:
// Registry is a collector for interceptors.
type Registry struct {
interceptors []Interceptor
}
// Add adds a new Interceptor to the registry.
func (i *Registry) Add(icpr Interceptor) {
i.interceptors = append(i.interceptors, icpr)
}
// Build constructs a single Interceptor from a InterceptorRegistry
func (i *Registry) Build() Interceptor {
if len(i.interceptors) == 0 {
return &NoOp{}
}
return NewChain(i.interceptors)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
可以看到,类方法就两个,一个Add就是添加,然后一个Build生成一个interceptor.Chain。所以这个interceptor.Registry的用处很明显就是构造interceptor的调用链。
从《用实例学习pion - rtp-forwarder》中还可以看到,这个interceptor.Registry并不是直接输入到webrtc.NewAPI里的,而是先经过了一个webrtc.WithInterceptorRegistry,这个webrtc.WithInterceptorRegistry更是简单:
// WithInterceptorRegistry allows providing Interceptors to the API.
// Settings should not be changed after passing the registry to an API.
func WithInterceptorRegistry(interceptorRegistry *interceptor.Registry) func(a *API) {
return func(a *API) {
a.interceptor = interceptorRegistry.Build()
}
}
2
3
4
5
6
7
直接就是调用上面那个interceptor.Registry里的Build函数。
# 在NewPeerConnection里
NewPeerConnection就是这个函数:
func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection, error)
在这个函数里与interceptor相关的就一句:
pc.interceptorRTCPWriter = api.interceptor.BindRTCPWriter(interceptor.RTCPWriterFunc(pc.writeRTCP))
显然这是给interceptor绑了一个实际进行RTCP写操作的函数pc.writeRTCP,这个函数显然是要负责把RTCP包发出去。返回的RTCPWriter被记录在了pc.interceptorRTCPWriter里。看看这个pc.interceptorRTCPWriter被调用的位置:
// WriteRTCP sends a user provided RTCP packet to the connected peer. If no peer is connected the
// packet is discarded. It also runs any configured interceptors.
func (pc *PeerConnection) WriteRTCP(pkts []rtcp.Packet) error {
_, err := pc.interceptorRTCPWriter.Write(pkts, make(interceptor.Attributes))
return err
}
2
3
4
5
6
嗯,直接就是封装在WriteRTCP里,很符合直觉。看过《pion/interceptor浅析》和《用实例学习pion interceptor - nack》就能明白,系统需要的发送RTCP包的过程都已经封装在interceptor里了,不需要用户手动去调用,这里的WriteRTCP只是留给用户自定义RTCP发包过程调用的。
最后当然也有关闭的操作,在PeerConnection.Close里,就是在关闭PeerConnection时要关闭interceptor,很好理解。
# 中场休息
截至目前,我们在NewPeerConnection找到了一堆初始化操作,我们看到:
BindRTCPWriter在NewPeerConnection里被调用,返回的RTCPWriter.Write在PeerConnection的WriteRTCP里调用,供用户发送一些自定义的RTCP包
根据《pion/interceptor浅析》,还差BindRTCPReader、BindRemoteStream、BindLocalStream的相关操作没用找到。
# 准备好,要开始加速了
在PeerConnection里,与RTP包收发相关的操作当属AddTrack和OnTrack。
其中,AddTrack接受一个TrackLocal,返回一个RTPSender:
func (pc *PeerConnection) AddTrack(track TrackLocal) (*RTPSender, error)
而OnTrack回调的输入也是一个TrackRemote和一个RTPReceiver:
func (pc *PeerConnection) OnTrack(f func(*TrackRemote, *RTPReceiver))
一眼看去,两个函数,AddTrack主发,OnTrack主收,其输入输出参数遥相呼应。显然,他们之间必有共通之处。
顺着AddTrack和OnTrack深入一层,我们就来到了Track的领域,这里的主角是TrackLocal和TrackRemote,分别主导RTP发送和接收的过程。下面两篇文章分别从TrackLocal和TrackRemote入手,深挖interceptor在发送RTP包和接收RTP包的场景下的调用方式。在开始前,你首先需要去《pion中的TrackLocal》和《pion中的TrackRemote》里看看TrackLocal和TrackRemote是什么以及怎么用。