Skip to content

Commit dce9704

Browse files
committed
Add InterceptorFactory
Interceptors are being accidentally misused by users. The issue is that an Interceptor can be re-used between multiple PeerConnections. Interceptors were designed to only be single PeerConnection aware, so state is being corrupted. Instead we are now going to provide InterceptorFactories. The default API of pion/webrtc will now be safe to use between PeerConnections. Resolves webrtc#1956
1 parent 1231f4f commit dce9704

File tree

5 files changed

+80
-44
lines changed

5 files changed

+80
-44
lines changed

api.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,22 @@ import (
77
"github.com/pion/logging"
88
)
99

10-
// API bundles the global functions of the WebRTC and ORTC API.
11-
// Some of these functions are also exported globally using the
12-
// defaultAPI object. Note that the global version of the API
13-
// may be phased out in the future.
10+
// API allows configuration of a PeerConnection
11+
// with APIs that are available in the standard. This
12+
// lets you set custom behavior via the SettingEngine, configure
13+
// codecs via the MediaEngine and define custom media behaviors via
14+
// Interceptors.
1415
type API struct {
15-
settingEngine *SettingEngine
16-
mediaEngine *MediaEngine
17-
interceptor interceptor.Interceptor
16+
settingEngine *SettingEngine
17+
mediaEngine *MediaEngine
18+
interceptorRegistry *interceptor.Registry
19+
20+
interceptor interceptor.Interceptor // Generated per PeerConnection
1821
}
1922

2023
// NewAPI Creates a new API object for keeping semi-global settings to WebRTC objects
2124
func NewAPI(options ...func(*API)) *API {
22-
a := &API{}
25+
a := &API{interceptor: &interceptor.NoOp{}}
2326

2427
for _, o := range options {
2528
o(a)
@@ -37,8 +40,8 @@ func NewAPI(options ...func(*API)) *API {
3740
a.mediaEngine = &MediaEngine{}
3841
}
3942

40-
if a.interceptor == nil {
41-
a.interceptor = &interceptor.NoOp{}
43+
if a.interceptorRegistry == nil {
44+
a.interceptorRegistry = &interceptor.Registry{}
4245
}
4346

4447
return a
@@ -68,6 +71,6 @@ func WithSettingEngine(s SettingEngine) func(a *API) {
6871
// Settings should not be changed after passing the registry to an API.
6972
func WithInterceptorRegistry(interceptorRegistry *interceptor.Registry) func(a *API) {
7073
return func(a *API) {
71-
a.interceptor = interceptorRegistry.Build()
74+
a.interceptorRegistry = interceptorRegistry
7275
}
7376
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/pion/datachannel v1.4.21
99
github.com/pion/dtls/v2 v2.0.9
1010
github.com/pion/ice/v2 v2.1.12
11-
github.com/pion/interceptor v0.0.19
11+
github.com/pion/interceptor v0.1.0
1212
github.com/pion/logging v0.2.2
1313
github.com/pion/randutil v0.1.0
1414
github.com/pion/rtcp v1.2.8

go.sum

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,15 @@ github.com/pion/dtls/v2 v2.0.9 h1:7Ow+V++YSZQMYzggI0P9vLJz/hUFcffsfGMfT/Qy+u8=
4343
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
4444
github.com/pion/ice/v2 v2.1.12 h1:ZDBuZz+fEI7iDifZCYFVzI4p0Foy0YhdSSZ87ZtRcRE=
4545
github.com/pion/ice/v2 v2.1.12/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
46-
github.com/pion/interceptor v0.0.19 h1:NkxrKHVH7ulrkVHTcZRJubgsF1oJeLQUvMsX1Kqm8to=
47-
github.com/pion/interceptor v0.0.19/go.mod h1:mv0Q0oPHxjRY8xz5v85G6aIqb1Tb0G0mxrZOaewHiVo=
46+
github.com/pion/interceptor v0.1.0 h1:SlXKaDlEvSl7cr4j8fJykzVz4UdH+7UDtcvx+u01wLU=
47+
github.com/pion/interceptor v0.1.0/go.mod h1:j5NIl3tJJPB3u8+Z2Xz8MZs/VV6rc+If9mXEKNuFmEM=
4848
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
4949
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
5050
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
5151
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
5252
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
5353
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
5454
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
55-
github.com/pion/rtcp v1.2.7/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
5655
github.com/pion/rtcp v1.2.8 h1:Cys8X6r0xxU65ESTmXkqr8eU1Q1Wx+lNkoZCUH4zD7E=
5756
github.com/pion/rtcp v1.2.8/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
5857
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=

interceptor_test.go

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,30 @@ func TestPeerConnection_Interceptor(t *testing.T) {
3333
assert.NoError(t, m.RegisterDefaultCodecs())
3434

3535
ir := &interceptor.Registry{}
36-
ir.Add(&mock_interceptor.Interceptor{
37-
BindLocalStreamFn: func(_ *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
38-
return interceptor.RTPWriterFunc(func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
39-
// set extension on outgoing packet
40-
header.Extension = true
41-
header.ExtensionProfile = 0xBEDE
42-
assert.NoError(t, header.SetExtension(2, []byte("foo")))
43-
44-
return writer.Write(header, payload, attributes)
45-
})
46-
},
47-
BindRemoteStreamFn: func(_ *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
48-
return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
49-
if a == nil {
50-
a = interceptor.Attributes{}
51-
}
52-
53-
a.Set("attribute", "value")
54-
return reader.Read(b, a)
55-
})
36+
ir.Add(&mock_interceptor.Factory{
37+
NewInterceptorFn: func(_ string) (interceptor.Interceptor, error) {
38+
return &mock_interceptor.Interceptor{
39+
BindLocalStreamFn: func(_ *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
40+
return interceptor.RTPWriterFunc(func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
41+
// set extension on outgoing packet
42+
header.Extension = true
43+
header.ExtensionProfile = 0xBEDE
44+
assert.NoError(t, header.SetExtension(2, []byte("foo")))
45+
46+
return writer.Write(header, payload, attributes)
47+
})
48+
},
49+
BindRemoteStreamFn: func(_ *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
50+
return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
51+
if a == nil {
52+
a = interceptor.Attributes{}
53+
}
54+
55+
a.Set("attribute", "value")
56+
return reader.Read(b, a)
57+
})
58+
},
59+
}, nil
5660
},
5761
})
5862

@@ -148,7 +152,9 @@ func Test_Interceptor_BindUnbind(t *testing.T) {
148152
},
149153
}
150154
ir := &interceptor.Registry{}
151-
ir.Add(mockInterceptor)
155+
ir.Add(&mock_interceptor.Factory{
156+
NewInterceptorFn: func(_ string) (interceptor.Interceptor, error) { return mockInterceptor, nil },
157+
})
152158

153159
sender, receiver, err := NewAPI(WithMediaEngine(m), WithInterceptorRegistry(ir)).newPair(Configuration{})
154160
assert.NoError(t, err)
@@ -209,3 +215,24 @@ func Test_Interceptor_BindUnbind(t *testing.T) {
209215
t.Errorf("CloseFn is expected to be called twice, but called %d times", cnt)
210216
}
211217
}
218+
219+
func Test_InterceptorRegistry_Build(t *testing.T) {
220+
registryBuildCount := 0
221+
222+
ir := &interceptor.Registry{}
223+
ir.Add(&mock_interceptor.Factory{
224+
NewInterceptorFn: func(_ string) (interceptor.Interceptor, error) {
225+
registryBuildCount++
226+
return &interceptor.NoOp{}, nil
227+
},
228+
})
229+
230+
peerConnectionA, err := NewAPI(WithInterceptorRegistry(ir)).NewPeerConnection(Configuration{})
231+
assert.NoError(t, err)
232+
233+
peerConnectionB, err := NewAPI(WithInterceptorRegistry(ir)).NewPeerConnection(Configuration{})
234+
assert.NoError(t, err)
235+
236+
assert.Equal(t, 2, registryBuildCount)
237+
closePairNow(t, peerConnectionA, peerConnectionB)
238+
}

peerconnection.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,22 @@ func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection,
134134
pc.iceConnectionState.Store(ICEConnectionStateNew)
135135
pc.connectionState.Store(PeerConnectionStateNew)
136136

137-
if !api.settingEngine.disableMediaEngineCopy {
138-
pc.api = &API{
139-
settingEngine: api.settingEngine,
140-
mediaEngine: api.mediaEngine.copy(),
141-
interceptor: api.interceptor,
142-
}
137+
i, err := api.interceptorRegistry.Build("")
138+
if err != nil {
139+
return nil, err
140+
}
141+
142+
pc.api = &API{
143+
settingEngine: api.settingEngine,
144+
interceptor: i,
145+
}
146+
147+
if api.settingEngine.disableMediaEngineCopy {
148+
pc.api.mediaEngine = api.mediaEngine
149+
} else {
150+
pc.api.mediaEngine = api.mediaEngine.copy()
143151
}
144152

145-
var err error
146153
if err = pc.initConfiguration(configuration); err != nil {
147154
return nil, err
148155
}
@@ -176,7 +183,7 @@ func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection,
176183
}
177184
})
178185

179-
pc.interceptorRTCPWriter = api.interceptor.BindRTCPWriter(interceptor.RTCPWriterFunc(pc.writeRTCP))
186+
pc.interceptorRTCPWriter = pc.api.interceptor.BindRTCPWriter(interceptor.RTCPWriterFunc(pc.writeRTCP))
180187

181188
return pc, nil
182189
}

0 commit comments

Comments
 (0)