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
是什么以及怎么用。