github.com/pion/webrtc/v4@v4.0.1/settingengine_test.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 //go:build !js 5 // +build !js 6 7 package webrtc 8 9 import ( 10 "context" 11 "net" 12 "testing" 13 "time" 14 15 "github.com/pion/dtls/v3/pkg/crypto/elliptic" 16 "github.com/pion/dtls/v3/pkg/protocol/handshake" 17 "github.com/pion/ice/v4" 18 "github.com/pion/stun/v3" 19 "github.com/pion/transport/v3/test" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func TestSetEphemeralUDPPortRange(t *testing.T) { 24 s := SettingEngine{} 25 26 if s.ephemeralUDP.PortMin != 0 || 27 s.ephemeralUDP.PortMax != 0 { 28 t.Fatalf("SettingEngine defaults aren't as expected.") 29 } 30 31 // set bad ephemeral ports 32 if err := s.SetEphemeralUDPPortRange(3000, 2999); err == nil { 33 t.Fatalf("Setting engine should fail bad ephemeral ports.") 34 } 35 36 if err := s.SetEphemeralUDPPortRange(3000, 4000); err != nil { 37 t.Fatalf("Setting engine failed valid port range: %s", err) 38 } 39 40 if s.ephemeralUDP.PortMin != 3000 || 41 s.ephemeralUDP.PortMax != 4000 { 42 t.Fatalf("Setting engine ports do not reflect expected range") 43 } 44 } 45 46 func TestSetConnectionTimeout(t *testing.T) { 47 s := SettingEngine{} 48 49 var nilDuration *time.Duration 50 assert.Equal(t, s.timeout.ICEDisconnectedTimeout, nilDuration) 51 assert.Equal(t, s.timeout.ICEFailedTimeout, nilDuration) 52 assert.Equal(t, s.timeout.ICEKeepaliveInterval, nilDuration) 53 54 s.SetICETimeouts(1*time.Second, 2*time.Second, 3*time.Second) 55 assert.Equal(t, *s.timeout.ICEDisconnectedTimeout, 1*time.Second) 56 assert.Equal(t, *s.timeout.ICEFailedTimeout, 2*time.Second) 57 assert.Equal(t, *s.timeout.ICEKeepaliveInterval, 3*time.Second) 58 } 59 60 func TestDetachDataChannels(t *testing.T) { 61 s := SettingEngine{} 62 63 if s.detach.DataChannels { 64 t.Fatalf("SettingEngine defaults aren't as expected.") 65 } 66 67 s.DetachDataChannels() 68 69 if !s.detach.DataChannels { 70 t.Fatalf("Failed to enable detached data channels.") 71 } 72 } 73 74 func TestSetNAT1To1IPs(t *testing.T) { 75 s := SettingEngine{} 76 if s.candidates.NAT1To1IPs != nil { 77 t.Errorf("Invalid default value") 78 } 79 if s.candidates.NAT1To1IPCandidateType != 0 { 80 t.Errorf("Invalid default value") 81 } 82 83 ips := []string{"1.2.3.4"} 84 typ := ICECandidateTypeHost 85 s.SetNAT1To1IPs(ips, typ) 86 if len(s.candidates.NAT1To1IPs) != 1 || s.candidates.NAT1To1IPs[0] != "1.2.3.4" { 87 t.Fatalf("Failed to set NAT1To1IPs") 88 } 89 if s.candidates.NAT1To1IPCandidateType != typ { 90 t.Fatalf("Failed to set NAT1To1IPCandidateType") 91 } 92 } 93 94 func TestSetAnsweringDTLSRole(t *testing.T) { 95 s := SettingEngine{} 96 assert.Error(t, s.SetAnsweringDTLSRole(DTLSRoleAuto), "SetAnsweringDTLSRole can only be called with DTLSRoleClient or DTLSRoleServer") 97 assert.Error(t, s.SetAnsweringDTLSRole(DTLSRole(0)), "SetAnsweringDTLSRole can only be called with DTLSRoleClient or DTLSRoleServer") 98 } 99 100 func TestSetReplayProtection(t *testing.T) { 101 s := SettingEngine{} 102 103 if s.replayProtection.DTLS != nil || 104 s.replayProtection.SRTP != nil || 105 s.replayProtection.SRTCP != nil { 106 t.Fatalf("SettingEngine defaults aren't as expected.") 107 } 108 109 s.SetDTLSReplayProtectionWindow(128) 110 s.SetSRTPReplayProtectionWindow(64) 111 s.SetSRTCPReplayProtectionWindow(32) 112 113 if s.replayProtection.DTLS == nil || 114 *s.replayProtection.DTLS != 128 { 115 t.Errorf("Failed to set DTLS replay protection window") 116 } 117 if s.replayProtection.SRTP == nil || 118 *s.replayProtection.SRTP != 64 { 119 t.Errorf("Failed to set SRTP replay protection window") 120 } 121 if s.replayProtection.SRTCP == nil || 122 *s.replayProtection.SRTCP != 32 { 123 t.Errorf("Failed to set SRTCP replay protection window") 124 } 125 } 126 127 func TestSettingEngine_SetICETCP(t *testing.T) { 128 report := test.CheckRoutines(t) 129 defer report() 130 131 listener, err := net.ListenTCP("tcp", &net.TCPAddr{}) 132 if err != nil { 133 panic(err) 134 } 135 136 defer func() { 137 _ = listener.Close() 138 }() 139 140 tcpMux := NewICETCPMux(nil, listener, 8) 141 142 defer func() { 143 _ = tcpMux.Close() 144 }() 145 146 settingEngine := SettingEngine{} 147 settingEngine.SetICETCPMux(tcpMux) 148 149 assert.Equal(t, tcpMux, settingEngine.iceTCPMux) 150 } 151 152 func TestSettingEngine_SetDisableMediaEngineCopy(t *testing.T) { 153 t.Run("Copy", func(t *testing.T) { 154 m := &MediaEngine{} 155 assert.NoError(t, m.RegisterDefaultCodecs()) 156 157 api := NewAPI(WithMediaEngine(m)) 158 159 offerer, answerer, err := api.newPair(Configuration{}) 160 assert.NoError(t, err) 161 162 _, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo) 163 assert.NoError(t, err) 164 165 assert.NoError(t, signalPair(offerer, answerer)) 166 167 // Assert that the MediaEngine the user created isn't modified 168 assert.False(t, m.negotiatedVideo) 169 assert.Empty(t, m.negotiatedVideoCodecs) 170 171 // Assert that the internal MediaEngine is modified 172 assert.True(t, offerer.api.mediaEngine.negotiatedVideo) 173 assert.NotEmpty(t, offerer.api.mediaEngine.negotiatedVideoCodecs) 174 175 closePairNow(t, offerer, answerer) 176 177 newOfferer, newAnswerer, err := api.newPair(Configuration{}) 178 assert.NoError(t, err) 179 180 // Assert that the first internal MediaEngine hasn't been cleared 181 assert.True(t, offerer.api.mediaEngine.negotiatedVideo) 182 assert.NotEmpty(t, offerer.api.mediaEngine.negotiatedVideoCodecs) 183 184 // Assert that the new internal MediaEngine isn't modified 185 assert.False(t, newOfferer.api.mediaEngine.negotiatedVideo) 186 assert.Empty(t, newAnswerer.api.mediaEngine.negotiatedVideoCodecs) 187 188 closePairNow(t, newOfferer, newAnswerer) 189 }) 190 191 t.Run("No Copy", func(t *testing.T) { 192 m := &MediaEngine{} 193 assert.NoError(t, m.RegisterDefaultCodecs()) 194 195 s := SettingEngine{} 196 s.DisableMediaEngineCopy(true) 197 198 api := NewAPI(WithMediaEngine(m), WithSettingEngine(s)) 199 200 offerer, answerer, err := api.newPair(Configuration{}) 201 assert.NoError(t, err) 202 203 _, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo) 204 assert.NoError(t, err) 205 206 assert.NoError(t, signalPair(offerer, answerer)) 207 208 // Assert that the user MediaEngine was modified, so no copy happened 209 assert.True(t, m.negotiatedVideo) 210 assert.NotEmpty(t, m.negotiatedVideoCodecs) 211 212 closePairNow(t, offerer, answerer) 213 214 offerer, answerer, err = api.newPair(Configuration{}) 215 assert.NoError(t, err) 216 217 // Assert that the new internal MediaEngine was modified, so no copy happened 218 assert.True(t, offerer.api.mediaEngine.negotiatedVideo) 219 assert.NotEmpty(t, offerer.api.mediaEngine.negotiatedVideoCodecs) 220 221 closePairNow(t, offerer, answerer) 222 }) 223 } 224 225 func TestSetDTLSRetransmissionInterval(t *testing.T) { 226 s := SettingEngine{} 227 228 if s.dtls.retransmissionInterval != 0 { 229 t.Fatalf("SettingEngine defaults aren't as expected.") 230 } 231 232 s.SetDTLSRetransmissionInterval(100 * time.Millisecond) 233 if s.dtls.retransmissionInterval == 0 || 234 s.dtls.retransmissionInterval != 100*time.Millisecond { 235 t.Errorf("Failed to set DTLS retransmission interval") 236 } 237 238 s.SetDTLSRetransmissionInterval(1 * time.Second) 239 if s.dtls.retransmissionInterval == 0 || 240 s.dtls.retransmissionInterval != 1*time.Second { 241 t.Errorf("Failed to set DTLS retransmission interval") 242 } 243 } 244 245 func TestSetDTLSEllipticCurves(t *testing.T) { 246 s := SettingEngine{} 247 248 if len(s.dtls.ellipticCurves) != 0 { 249 t.Fatalf("SettingEngine defaults aren't as expected.") 250 } 251 252 s.SetDTLSEllipticCurves(elliptic.P256) 253 if len(s.dtls.ellipticCurves) == 0 || 254 s.dtls.ellipticCurves[0] != elliptic.P256 { 255 t.Errorf("Failed to set DTLS elliptic curves") 256 } 257 } 258 259 func TestSetDTLSHandShakeTimeout(*testing.T) { 260 s := SettingEngine{} 261 262 s.SetDTLSConnectContextMaker(func() (context.Context, func()) { 263 return context.WithTimeout(context.Background(), 60*time.Second) 264 }) 265 } 266 267 func TestSetSCTPMaxReceiverBufferSize(t *testing.T) { 268 s := SettingEngine{} 269 assert.Equal(t, uint32(0), s.sctp.maxReceiveBufferSize) 270 271 expSize := uint32(4 * 1024 * 1024) 272 s.SetSCTPMaxReceiveBufferSize(expSize) 273 assert.Equal(t, expSize, s.sctp.maxReceiveBufferSize) 274 } 275 276 func TestSetSCTPRTOMax(t *testing.T) { 277 s := SettingEngine{} 278 assert.Equal(t, time.Duration(0), s.sctp.rtoMax) 279 280 expSize := time.Second 281 s.SetSCTPRTOMax(expSize) 282 assert.Equal(t, expSize, s.sctp.rtoMax) 283 } 284 285 func TestSetICEBindingRequestHandler(t *testing.T) { 286 seenICEControlled, seenICEControlledCancel := context.WithCancel(context.Background()) 287 seenICEControlling, seenICEControllingCancel := context.WithCancel(context.Background()) 288 289 s := SettingEngine{} 290 s.SetICEBindingRequestHandler(func(m *stun.Message, _, _ ice.Candidate, _ *ice.CandidatePair) bool { 291 for _, a := range m.Attributes { 292 switch a.Type { 293 case stun.AttrICEControlled: 294 seenICEControlledCancel() 295 case stun.AttrICEControlling: 296 seenICEControllingCancel() 297 default: 298 } 299 } 300 301 return false 302 }) 303 304 pcOffer, pcAnswer, err := NewAPI(WithSettingEngine(s)).newPair(Configuration{}) 305 assert.NoError(t, err) 306 307 assert.NoError(t, signalPair(pcOffer, pcAnswer)) 308 309 <-seenICEControlled.Done() 310 <-seenICEControlling.Done() 311 closePairNow(t, pcOffer, pcAnswer) 312 } 313 314 func TestSetHooks(t *testing.T) { 315 s := SettingEngine{} 316 317 if s.dtls.clientHelloMessageHook != nil || 318 s.dtls.serverHelloMessageHook != nil || 319 s.dtls.certificateRequestMessageHook != nil { 320 t.Fatalf("SettingEngine defaults aren't as expected.") 321 } 322 323 s.SetDTLSClientHelloMessageHook(func(msg handshake.MessageClientHello) handshake.Message { 324 return &msg 325 }) 326 s.SetDTLSServerHelloMessageHook(func(msg handshake.MessageServerHello) handshake.Message { 327 return &msg 328 }) 329 s.SetDTLSCertificateRequestMessageHook(func(msg handshake.MessageCertificateRequest) handshake.Message { 330 return &msg 331 }) 332 333 if s.dtls.clientHelloMessageHook == nil { 334 t.Errorf("Failed to set DTLS Client Hello Hook") 335 } 336 if s.dtls.serverHelloMessageHook == nil { 337 t.Errorf("Failed to set DTLS Server Hello Hook") 338 } 339 if s.dtls.certificateRequestMessageHook == nil { 340 t.Errorf("Failed to set DTLS Certificate Request Hook") 341 } 342 } 343 344 func TestSetFireOnTrackBeforeFirstRTP(t *testing.T) { 345 lim := test.TimeOut(time.Second * 30) 346 defer lim.Stop() 347 348 report := test.CheckRoutines(t) 349 defer report() 350 351 s := SettingEngine{} 352 s.SetFireOnTrackBeforeFirstRTP(true) 353 354 mediaEngineOne := &MediaEngine{} 355 assert.NoError(t, mediaEngineOne.RegisterCodec(RTPCodecParameters{ 356 RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, 357 PayloadType: 100, 358 }, RTPCodecTypeVideo)) 359 360 mediaEngineTwo := &MediaEngine{} 361 assert.NoError(t, mediaEngineTwo.RegisterCodec(RTPCodecParameters{ 362 RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, 363 PayloadType: 200, 364 }, RTPCodecTypeVideo)) 365 366 offerer, err := NewAPI(WithMediaEngine(mediaEngineOne), WithSettingEngine(s)).NewPeerConnection(Configuration{}) 367 assert.NoError(t, err) 368 369 answerer, err := NewAPI(WithMediaEngine(mediaEngineTwo)).NewPeerConnection(Configuration{}) 370 assert.NoError(t, err) 371 372 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 373 assert.NoError(t, err) 374 375 _, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo) 376 assert.NoError(t, err) 377 378 _, err = answerer.AddTrack(track) 379 assert.NoError(t, err) 380 381 onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background()) 382 offerer.OnTrack(func(track *TrackRemote, _ *RTPReceiver) { 383 _, _, err = track.Read(make([]byte, 1500)) 384 assert.NoError(t, err) 385 assert.Equal(t, track.PayloadType(), PayloadType(100)) 386 assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8") 387 388 onTrackFiredFunc() 389 }) 390 391 assert.NoError(t, signalPair(offerer, answerer)) 392 393 sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{track}) 394 395 closePairNow(t, offerer, answerer) 396 }