github.com/pion/webrtc/v3@v3.2.24/rtpsender_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 "errors" 12 "io" 13 "sync/atomic" 14 "testing" 15 "time" 16 17 "github.com/pion/transport/v2/test" 18 "github.com/pion/webrtc/v3/pkg/media" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 func Test_RTPSender_ReplaceTrack(t *testing.T) { 23 lim := test.TimeOut(time.Second * 10) 24 defer lim.Stop() 25 26 report := test.CheckRoutines(t) 27 defer report() 28 29 s := SettingEngine{} 30 s.DisableSRTPReplayProtection(true) 31 32 m := &MediaEngine{} 33 assert.NoError(t, m.RegisterDefaultCodecs()) 34 35 sender, receiver, err := NewAPI(WithMediaEngine(m), WithSettingEngine(s)).newPair(Configuration{}) 36 assert.NoError(t, err) 37 38 trackA, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 39 assert.NoError(t, err) 40 41 trackB, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeH264}, "video", "pion") 42 assert.NoError(t, err) 43 44 rtpSender, err := sender.AddTrack(trackA) 45 assert.NoError(t, err) 46 47 seenPacketA, seenPacketACancel := context.WithCancel(context.Background()) 48 seenPacketB, seenPacketBCancel := context.WithCancel(context.Background()) 49 50 var onTrackCount uint64 51 receiver.OnTrack(func(track *TrackRemote, _ *RTPReceiver) { 52 assert.Equal(t, uint64(1), atomic.AddUint64(&onTrackCount, 1)) 53 54 for { 55 pkt, _, err := track.ReadRTP() 56 if err != nil { 57 assert.True(t, errors.Is(io.EOF, err)) 58 return 59 } 60 61 switch { 62 case pkt.Payload[len(pkt.Payload)-1] == 0xAA: 63 assert.Equal(t, track.Codec().MimeType, MimeTypeVP8) 64 seenPacketACancel() 65 case pkt.Payload[len(pkt.Payload)-1] == 0xBB: 66 assert.Equal(t, track.Codec().MimeType, MimeTypeH264) 67 seenPacketBCancel() 68 default: 69 t.Fatalf("Unexpected RTP Data % 02x", pkt.Payload[len(pkt.Payload)-1]) 70 } 71 } 72 }) 73 74 assert.NoError(t, signalPair(sender, receiver)) 75 76 // Block Until packet with 0xAA has been seen 77 func() { 78 for range time.Tick(time.Millisecond * 20) { 79 select { 80 case <-seenPacketA.Done(): 81 return 82 default: 83 assert.NoError(t, trackA.WriteSample(media.Sample{Data: []byte{0xAA}, Duration: time.Second})) 84 } 85 } 86 }() 87 88 assert.NoError(t, rtpSender.ReplaceTrack(trackB)) 89 90 // Block Until packet with 0xBB has been seen 91 func() { 92 for range time.Tick(time.Millisecond * 20) { 93 select { 94 case <-seenPacketB.Done(): 95 return 96 default: 97 assert.NoError(t, trackB.WriteSample(media.Sample{Data: []byte{0xBB}, Duration: time.Second})) 98 } 99 } 100 }() 101 102 closePairNow(t, sender, receiver) 103 } 104 105 func Test_RTPSender_GetParameters(t *testing.T) { 106 lim := test.TimeOut(time.Second * 10) 107 defer lim.Stop() 108 109 report := test.CheckRoutines(t) 110 defer report() 111 112 offerer, answerer, err := newPair() 113 assert.NoError(t, err) 114 115 rtpTransceiver, err := offerer.AddTransceiverFromKind(RTPCodecTypeVideo) 116 assert.NoError(t, err) 117 118 assert.NoError(t, signalPair(offerer, answerer)) 119 120 parameters := rtpTransceiver.Sender().GetParameters() 121 assert.NotEqual(t, 0, len(parameters.Codecs)) 122 assert.Equal(t, 1, len(parameters.Encodings)) 123 assert.Equal(t, rtpTransceiver.Sender().trackEncodings[0].ssrc, parameters.Encodings[0].SSRC) 124 assert.Equal(t, "", parameters.Encodings[0].RID) 125 126 closePairNow(t, offerer, answerer) 127 } 128 129 func Test_RTPSender_GetParameters_WithRID(t *testing.T) { 130 lim := test.TimeOut(time.Second * 10) 131 defer lim.Stop() 132 133 report := test.CheckRoutines(t) 134 defer report() 135 136 offerer, answerer, err := newPair() 137 assert.NoError(t, err) 138 139 rtpTransceiver, err := offerer.AddTransceiverFromKind(RTPCodecTypeVideo) 140 assert.NoError(t, err) 141 142 assert.NoError(t, signalPair(offerer, answerer)) 143 144 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("moo")) 145 assert.NoError(t, err) 146 147 err = rtpTransceiver.setSendingTrack(track) 148 assert.NoError(t, err) 149 150 parameters := rtpTransceiver.Sender().GetParameters() 151 assert.Equal(t, track.RID(), parameters.Encodings[0].RID) 152 153 closePairNow(t, offerer, answerer) 154 } 155 156 func Test_RTPSender_SetReadDeadline(t *testing.T) { 157 lim := test.TimeOut(time.Second * 30) 158 defer lim.Stop() 159 160 report := test.CheckRoutines(t) 161 defer report() 162 163 sender, receiver, wan := createVNetPair(t) 164 165 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 166 assert.NoError(t, err) 167 168 rtpSender, err := sender.AddTrack(track) 169 assert.NoError(t, err) 170 171 peerConnectionsConnected := untilConnectionState(PeerConnectionStateConnected, sender, receiver) 172 173 assert.NoError(t, signalPair(sender, receiver)) 174 175 peerConnectionsConnected.Wait() 176 177 assert.NoError(t, rtpSender.SetReadDeadline(time.Now().Add(1*time.Second))) 178 _, _, err = rtpSender.ReadRTCP() 179 assert.Error(t, err) 180 181 assert.NoError(t, wan.Stop()) 182 closePairNow(t, sender, receiver) 183 } 184 185 func Test_RTPSender_ReplaceTrack_InvalidTrackKindChange(t *testing.T) { 186 lim := test.TimeOut(time.Second * 10) 187 defer lim.Stop() 188 189 report := test.CheckRoutines(t) 190 defer report() 191 192 sender, receiver, err := newPair() 193 assert.NoError(t, err) 194 195 trackA, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 196 assert.NoError(t, err) 197 198 trackB, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeOpus}, "audio", "pion") 199 assert.NoError(t, err) 200 201 rtpSender, err := sender.AddTrack(trackA) 202 assert.NoError(t, err) 203 204 assert.NoError(t, signalPair(sender, receiver)) 205 206 seenPacket, seenPacketCancel := context.WithCancel(context.Background()) 207 receiver.OnTrack(func(_ *TrackRemote, _ *RTPReceiver) { 208 seenPacketCancel() 209 }) 210 211 func() { 212 for range time.Tick(time.Millisecond * 20) { 213 select { 214 case <-seenPacket.Done(): 215 return 216 default: 217 assert.NoError(t, trackA.WriteSample(media.Sample{Data: []byte{0xAA}, Duration: time.Second})) 218 } 219 } 220 }() 221 222 assert.True(t, errors.Is(rtpSender.ReplaceTrack(trackB), ErrRTPSenderNewTrackHasIncorrectKind)) 223 224 closePairNow(t, sender, receiver) 225 } 226 227 func Test_RTPSender_ReplaceTrack_InvalidCodecChange(t *testing.T) { 228 lim := test.TimeOut(time.Second * 10) 229 defer lim.Stop() 230 231 report := test.CheckRoutines(t) 232 defer report() 233 234 sender, receiver, err := newPair() 235 assert.NoError(t, err) 236 237 trackA, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 238 assert.NoError(t, err) 239 240 trackB, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP9}, "video", "pion") 241 assert.NoError(t, err) 242 243 rtpSender, err := sender.AddTrack(trackA) 244 assert.NoError(t, err) 245 246 err = rtpSender.rtpTransceiver.SetCodecPreferences([]RTPCodecParameters{{ 247 RTPCodecCapability: RTPCodecCapability{MimeType: MimeTypeVP8}, 248 PayloadType: 96, 249 }}) 250 assert.NoError(t, err) 251 252 assert.NoError(t, signalPair(sender, receiver)) 253 254 seenPacket, seenPacketCancel := context.WithCancel(context.Background()) 255 receiver.OnTrack(func(_ *TrackRemote, _ *RTPReceiver) { 256 seenPacketCancel() 257 }) 258 259 func() { 260 for range time.Tick(time.Millisecond * 20) { 261 select { 262 case <-seenPacket.Done(): 263 return 264 default: 265 assert.NoError(t, trackA.WriteSample(media.Sample{Data: []byte{0xAA}, Duration: time.Second})) 266 } 267 } 268 }() 269 270 assert.True(t, errors.Is(rtpSender.ReplaceTrack(trackB), ErrUnsupportedCodec)) 271 272 closePairNow(t, sender, receiver) 273 } 274 275 func Test_RTPSender_GetParameters_NilTrack(t *testing.T) { 276 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 277 assert.NoError(t, err) 278 279 peerConnection, err := NewPeerConnection(Configuration{}) 280 assert.NoError(t, err) 281 282 rtpSender, err := peerConnection.AddTrack(track) 283 assert.NoError(t, err) 284 285 assert.NoError(t, rtpSender.ReplaceTrack(nil)) 286 rtpSender.GetParameters() 287 288 assert.NoError(t, peerConnection.Close()) 289 } 290 291 func Test_RTPSender_Send(t *testing.T) { 292 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 293 assert.NoError(t, err) 294 295 peerConnection, err := NewPeerConnection(Configuration{}) 296 assert.NoError(t, err) 297 298 rtpSender, err := peerConnection.AddTrack(track) 299 assert.NoError(t, err) 300 301 parameter := rtpSender.GetParameters() 302 err = rtpSender.Send(parameter) 303 <-rtpSender.sendCalled 304 assert.NoError(t, err) 305 306 assert.NoError(t, peerConnection.Close()) 307 } 308 309 func Test_RTPSender_Send_Called_Once(t *testing.T) { 310 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 311 assert.NoError(t, err) 312 313 peerConnection, err := NewPeerConnection(Configuration{}) 314 assert.NoError(t, err) 315 316 rtpSender, err := peerConnection.AddTrack(track) 317 assert.NoError(t, err) 318 319 parameter := rtpSender.GetParameters() 320 err = rtpSender.Send(parameter) 321 <-rtpSender.sendCalled 322 assert.NoError(t, err) 323 324 err = rtpSender.Send(parameter) 325 assert.Equal(t, errRTPSenderSendAlreadyCalled, err) 326 327 assert.NoError(t, peerConnection.Close()) 328 } 329 330 func Test_RTPSender_Send_Track_Removed(t *testing.T) { 331 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 332 assert.NoError(t, err) 333 334 peerConnection, err := NewPeerConnection(Configuration{}) 335 assert.NoError(t, err) 336 337 rtpSender, err := peerConnection.AddTrack(track) 338 assert.NoError(t, err) 339 340 parameter := rtpSender.GetParameters() 341 assert.NoError(t, peerConnection.RemoveTrack(rtpSender)) 342 assert.Equal(t, errRTPSenderTrackRemoved, rtpSender.Send(parameter)) 343 344 assert.NoError(t, peerConnection.Close()) 345 } 346 347 func Test_RTPSender_Add_Encoding(t *testing.T) { 348 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 349 assert.NoError(t, err) 350 351 peerConnection, err := NewPeerConnection(Configuration{}) 352 assert.NoError(t, err) 353 354 rtpSender, err := peerConnection.AddTrack(track) 355 assert.NoError(t, err) 356 357 assert.Equal(t, errRTPSenderTrackNil, rtpSender.AddEncoding(nil)) 358 359 track1, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 360 assert.NoError(t, err) 361 assert.Equal(t, errRTPSenderRidNil, rtpSender.AddEncoding(track1)) 362 363 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("h")) 364 assert.NoError(t, err) 365 assert.Equal(t, errRTPSenderNoBaseEncoding, rtpSender.AddEncoding(track1)) 366 367 track, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("q")) 368 assert.NoError(t, err) 369 370 rtpSender, err = peerConnection.AddTrack(track) 371 assert.NoError(t, err) 372 373 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video1", "pion", WithRTPStreamID("h")) 374 assert.NoError(t, err) 375 assert.Equal(t, errRTPSenderBaseEncodingMismatch, rtpSender.AddEncoding(track1)) 376 377 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion1", WithRTPStreamID("h")) 378 assert.NoError(t, err) 379 assert.Equal(t, errRTPSenderBaseEncodingMismatch, rtpSender.AddEncoding(track1)) 380 381 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeOpus}, "video", "pion", WithRTPStreamID("h")) 382 assert.NoError(t, err) 383 assert.Equal(t, errRTPSenderBaseEncodingMismatch, rtpSender.AddEncoding(track1)) 384 385 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("q")) 386 assert.NoError(t, err) 387 assert.Equal(t, errRTPSenderRIDCollision, rtpSender.AddEncoding(track1)) 388 389 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("h")) 390 assert.NoError(t, err) 391 assert.NoError(t, rtpSender.AddEncoding(track1)) 392 393 err = rtpSender.Send(rtpSender.GetParameters()) 394 assert.NoError(t, err) 395 396 track1, err = NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("f")) 397 assert.NoError(t, err) 398 assert.Equal(t, errRTPSenderSendAlreadyCalled, rtpSender.AddEncoding(track1)) 399 400 err = rtpSender.Stop() 401 assert.NoError(t, err) 402 403 assert.Equal(t, errRTPSenderStopped, rtpSender.AddEncoding(track1)) 404 405 assert.NoError(t, peerConnection.Close()) 406 }