github.com/pion/webrtc/v3@v3.2.24/track_local_static_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 "testing" 13 "time" 14 15 "github.com/pion/rtp" 16 "github.com/pion/transport/v2/test" 17 "github.com/stretchr/testify/assert" 18 ) 19 20 // If a remote doesn't support a Codec used by a `TrackLocalStatic` 21 // an error should be returned to the user 22 func Test_TrackLocalStatic_NoCodecIntersection(t *testing.T) { 23 lim := test.TimeOut(time.Second * 30) 24 defer lim.Stop() 25 26 report := test.CheckRoutines(t) 27 defer report() 28 29 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 30 assert.NoError(t, err) 31 32 t.Run("Offerer", func(t *testing.T) { 33 pc, err := NewPeerConnection(Configuration{}) 34 assert.NoError(t, err) 35 36 noCodecPC, err := NewAPI().NewPeerConnection(Configuration{}) 37 assert.NoError(t, err) 38 39 _, err = pc.AddTrack(track) 40 assert.NoError(t, err) 41 42 assert.ErrorIs(t, signalPair(pc, noCodecPC), ErrUnsupportedCodec) 43 44 closePairNow(t, noCodecPC, pc) 45 }) 46 47 t.Run("Answerer", func(t *testing.T) { 48 pc, err := NewPeerConnection(Configuration{}) 49 assert.NoError(t, err) 50 51 m := &MediaEngine{} 52 assert.NoError(t, m.RegisterCodec(RTPCodecParameters{ 53 RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP9", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, 54 PayloadType: 96, 55 }, RTPCodecTypeVideo)) 56 57 vp9OnlyPC, err := NewAPI(WithMediaEngine(m)).NewPeerConnection(Configuration{}) 58 assert.NoError(t, err) 59 60 _, err = vp9OnlyPC.AddTransceiverFromKind(RTPCodecTypeVideo) 61 assert.NoError(t, err) 62 63 _, err = pc.AddTrack(track) 64 assert.NoError(t, err) 65 66 assert.True(t, errors.Is(signalPair(vp9OnlyPC, pc), ErrUnsupportedCodec)) 67 68 closePairNow(t, vp9OnlyPC, pc) 69 }) 70 71 t.Run("Local", func(t *testing.T) { 72 offerer, answerer, err := newPair() 73 assert.NoError(t, err) 74 75 invalidCodecTrack, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: "video/invalid-codec"}, "video", "pion") 76 assert.NoError(t, err) 77 78 _, err = offerer.AddTrack(invalidCodecTrack) 79 assert.NoError(t, err) 80 81 assert.True(t, errors.Is(signalPair(offerer, answerer), ErrUnsupportedCodec)) 82 closePairNow(t, offerer, answerer) 83 }) 84 } 85 86 // Assert that Bind/Unbind happens when expected 87 func Test_TrackLocalStatic_Closed(t *testing.T) { 88 lim := test.TimeOut(time.Second * 30) 89 defer lim.Stop() 90 91 report := test.CheckRoutines(t) 92 defer report() 93 94 pcOffer, pcAnswer, err := newPair() 95 assert.NoError(t, err) 96 97 _, err = pcAnswer.AddTransceiverFromKind(RTPCodecTypeVideo) 98 assert.NoError(t, err) 99 100 vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 101 assert.NoError(t, err) 102 103 _, err = pcOffer.AddTrack(vp8Writer) 104 assert.NoError(t, err) 105 106 assert.Equal(t, len(vp8Writer.bindings), 0, "No binding should exist before signaling") 107 108 assert.NoError(t, signalPair(pcOffer, pcAnswer)) 109 110 assert.Equal(t, len(vp8Writer.bindings), 1, "binding should exist after signaling") 111 112 closePairNow(t, pcOffer, pcAnswer) 113 114 assert.Equal(t, len(vp8Writer.bindings), 0, "No binding should exist after close") 115 } 116 117 func Test_TrackLocalStatic_PayloadType(t *testing.T) { 118 lim := test.TimeOut(time.Second * 30) 119 defer lim.Stop() 120 121 report := test.CheckRoutines(t) 122 defer report() 123 124 mediaEngineOne := &MediaEngine{} 125 assert.NoError(t, mediaEngineOne.RegisterCodec(RTPCodecParameters{ 126 RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, 127 PayloadType: 100, 128 }, RTPCodecTypeVideo)) 129 130 mediaEngineTwo := &MediaEngine{} 131 assert.NoError(t, mediaEngineTwo.RegisterCodec(RTPCodecParameters{ 132 RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, 133 PayloadType: 200, 134 }, RTPCodecTypeVideo)) 135 136 offerer, err := NewAPI(WithMediaEngine(mediaEngineOne)).NewPeerConnection(Configuration{}) 137 assert.NoError(t, err) 138 139 answerer, err := NewAPI(WithMediaEngine(mediaEngineTwo)).NewPeerConnection(Configuration{}) 140 assert.NoError(t, err) 141 142 track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 143 assert.NoError(t, err) 144 145 _, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo) 146 assert.NoError(t, err) 147 148 _, err = answerer.AddTrack(track) 149 assert.NoError(t, err) 150 151 onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background()) 152 offerer.OnTrack(func(track *TrackRemote, r *RTPReceiver) { 153 assert.Equal(t, track.PayloadType(), PayloadType(100)) 154 assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8") 155 156 onTrackFiredFunc() 157 }) 158 159 assert.NoError(t, signalPair(offerer, answerer)) 160 161 sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{track}) 162 163 closePairNow(t, offerer, answerer) 164 } 165 166 // Assert that writing to a Track doesn't modify the input 167 // Even though we can pass a pointer we shouldn't modify the incoming value 168 func Test_TrackLocalStatic_Mutate_Input(t *testing.T) { 169 lim := test.TimeOut(time.Second * 30) 170 defer lim.Stop() 171 172 report := test.CheckRoutines(t) 173 defer report() 174 175 pcOffer, pcAnswer, err := newPair() 176 assert.NoError(t, err) 177 178 vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 179 assert.NoError(t, err) 180 181 _, err = pcOffer.AddTrack(vp8Writer) 182 assert.NoError(t, err) 183 184 assert.NoError(t, signalPair(pcOffer, pcAnswer)) 185 186 pkt := &rtp.Packet{Header: rtp.Header{SSRC: 1, PayloadType: 1}} 187 assert.NoError(t, vp8Writer.WriteRTP(pkt)) 188 189 assert.Equal(t, pkt.Header.SSRC, uint32(1)) 190 assert.Equal(t, pkt.Header.PayloadType, uint8(1)) 191 192 closePairNow(t, pcOffer, pcAnswer) 193 } 194 195 // Assert that writing to a Track that has Binded (but not connected) 196 // does not block 197 func Test_TrackLocalStatic_Binding_NonBlocking(t *testing.T) { 198 lim := test.TimeOut(time.Second * 5) 199 defer lim.Stop() 200 201 report := test.CheckRoutines(t) 202 defer report() 203 204 pcOffer, pcAnswer, err := newPair() 205 assert.NoError(t, err) 206 207 _, err = pcOffer.AddTransceiverFromKind(RTPCodecTypeVideo) 208 assert.NoError(t, err) 209 210 vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 211 assert.NoError(t, err) 212 213 _, err = pcAnswer.AddTrack(vp8Writer) 214 assert.NoError(t, err) 215 216 offer, err := pcOffer.CreateOffer(nil) 217 assert.NoError(t, err) 218 219 assert.NoError(t, pcAnswer.SetRemoteDescription(offer)) 220 221 answer, err := pcAnswer.CreateAnswer(nil) 222 assert.NoError(t, err) 223 assert.NoError(t, pcAnswer.SetLocalDescription(answer)) 224 225 _, err = vp8Writer.Write(make([]byte, 20)) 226 assert.NoError(t, err) 227 228 closePairNow(t, pcOffer, pcAnswer) 229 } 230 231 func BenchmarkTrackLocalWrite(b *testing.B) { 232 offerPC, answerPC, err := newPair() 233 defer closePairNow(b, offerPC, answerPC) 234 if err != nil { 235 b.Fatalf("Failed to create a PC pair for testing") 236 } 237 238 track, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") 239 assert.NoError(b, err) 240 241 _, err = offerPC.AddTrack(track) 242 assert.NoError(b, err) 243 244 _, err = answerPC.AddTransceiverFromKind(RTPCodecTypeVideo) 245 assert.NoError(b, err) 246 247 b.SetBytes(1024) 248 249 buf := make([]byte, 1024) 250 for i := 0; i < b.N; i++ { 251 _, err := track.Write(buf) 252 assert.NoError(b, err) 253 } 254 }