github.com/pion/webrtc/v4@v4.0.1/pkg/media/samplebuilder/samplebuilder_test.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 package samplebuilder 5 6 import ( 7 "fmt" 8 "runtime" 9 "sync/atomic" 10 "testing" 11 "time" 12 13 "github.com/pion/rtp" 14 "github.com/pion/webrtc/v4/pkg/media" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 type sampleBuilderTest struct { 19 message string 20 packets []*rtp.Packet 21 withHeadChecker bool 22 withRTPHeader bool 23 headBytes []byte 24 samples []*media.Sample 25 maxLate uint16 26 maxLateTimestamp uint32 27 } 28 29 type fakeDepacketizer struct { 30 headChecker bool 31 headBytes []byte 32 alwaysHead bool 33 } 34 35 func (f *fakeDepacketizer) Unmarshal(r []byte) ([]byte, error) { 36 return r, nil 37 } 38 39 func (f *fakeDepacketizer) IsPartitionHead(payload []byte) bool { 40 if !f.headChecker { 41 // simulates a bug in the 3.0 version 42 // the tests should be fixed to not assume the bug 43 return true 44 } 45 46 // skip padding 47 if len(payload) < 1 { 48 return false 49 } 50 51 if f.alwaysHead { 52 return true 53 } 54 55 for _, b := range f.headBytes { 56 if payload[0] == b { 57 return true 58 } 59 } 60 return false 61 } 62 63 func (f *fakeDepacketizer) IsPartitionTail(marker bool, _ []byte) bool { 64 return marker 65 } 66 67 func TestSampleBuilder(t *testing.T) { 68 testData := []sampleBuilderTest{ 69 { 70 message: "SampleBuilder shouldn't emit anything if only one RTP packet has been pushed", 71 packets: []*rtp.Packet{ 72 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 73 }, 74 samples: []*media.Sample{}, 75 maxLate: 50, 76 maxLateTimestamp: 0, 77 }, 78 { 79 message: "SampleBuilder shouldn't emit anything if only one RTP packet has been pushed even if the market bit is set", 80 packets: []*rtp.Packet{ 81 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5, Marker: true}, Payload: []byte{0x01}}, 82 }, 83 samples: []*media.Sample{}, 84 maxLate: 50, 85 maxLateTimestamp: 0, 86 }, 87 { 88 message: "SampleBuilder should emit two packets, we had three packets with unique timestamps", 89 packets: []*rtp.Packet{ 90 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 91 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 6}, Payload: []byte{0x02}}, 92 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 7}, Payload: []byte{0x03}}, 93 }, 94 samples: []*media.Sample{ 95 {Data: []byte{0x01}, Duration: time.Second, PacketTimestamp: 5}, 96 {Data: []byte{0x02}, Duration: time.Second, PacketTimestamp: 6}, 97 }, 98 maxLate: 50, 99 maxLateTimestamp: 0, 100 }, 101 { 102 message: "SampleBuilder should emit one packet, we had a packet end of sequence marker and run out of space", 103 packets: []*rtp.Packet{ 104 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5, Marker: true}, Payload: []byte{0x01}}, 105 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 7}, Payload: []byte{0x02}}, 106 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 9}, Payload: []byte{0x03}}, 107 {Header: rtp.Header{SequenceNumber: 5006, Timestamp: 11}, Payload: []byte{0x04}}, 108 {Header: rtp.Header{SequenceNumber: 5008, Timestamp: 13}, Payload: []byte{0x05}}, 109 {Header: rtp.Header{SequenceNumber: 5010, Timestamp: 15}, Payload: []byte{0x06}}, 110 {Header: rtp.Header{SequenceNumber: 5012, Timestamp: 17}, Payload: []byte{0x07}}, 111 }, 112 samples: []*media.Sample{ 113 {Data: []byte{0x01}, Duration: time.Second * 2, PacketTimestamp: 5}, 114 }, 115 maxLate: 5, 116 maxLateTimestamp: 0, 117 }, 118 { 119 message: "SampleBuilder shouldn't emit any packet, we do not have a valid end of sequence and run out of space", 120 packets: []*rtp.Packet{ 121 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 122 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 7}, Payload: []byte{0x02}}, 123 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 9}, Payload: []byte{0x03}}, 124 {Header: rtp.Header{SequenceNumber: 5006, Timestamp: 11}, Payload: []byte{0x04}}, 125 {Header: rtp.Header{SequenceNumber: 5008, Timestamp: 13}, Payload: []byte{0x05}}, 126 {Header: rtp.Header{SequenceNumber: 5010, Timestamp: 15}, Payload: []byte{0x06}}, 127 {Header: rtp.Header{SequenceNumber: 5012, Timestamp: 17}, Payload: []byte{0x07}}, 128 }, 129 samples: []*media.Sample{}, 130 maxLate: 5, 131 maxLateTimestamp: 0, 132 }, 133 { 134 message: "SampleBuilder should emit one packet, we had a packet end of sequence marker and run out of space", 135 packets: []*rtp.Packet{ 136 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5, Marker: true}, Payload: []byte{0x01}}, 137 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 7, Marker: true}, Payload: []byte{0x02}}, 138 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 9}, Payload: []byte{0x03}}, 139 {Header: rtp.Header{SequenceNumber: 5006, Timestamp: 11}, Payload: []byte{0x04}}, 140 {Header: rtp.Header{SequenceNumber: 5008, Timestamp: 13}, Payload: []byte{0x05}}, 141 {Header: rtp.Header{SequenceNumber: 5010, Timestamp: 15}, Payload: []byte{0x06}}, 142 {Header: rtp.Header{SequenceNumber: 5012, Timestamp: 17}, Payload: []byte{0x07}}, 143 }, 144 samples: []*media.Sample{ 145 {Data: []byte{0x01}, Duration: time.Second * 2, PacketTimestamp: 5}, 146 {Data: []byte{0x02}, Duration: time.Second * 2, PacketTimestamp: 7, PrevDroppedPackets: 1}, 147 }, 148 maxLate: 5, 149 maxLateTimestamp: 0, 150 }, 151 { 152 message: "SampleBuilder should emit one packet, we had two packets but two with duplicate timestamps", 153 packets: []*rtp.Packet{ 154 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 155 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 6}, Payload: []byte{0x02}}, 156 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 6}, Payload: []byte{0x03}}, 157 {Header: rtp.Header{SequenceNumber: 5003, Timestamp: 7}, Payload: []byte{0x04}}, 158 }, 159 samples: []*media.Sample{ 160 {Data: []byte{0x01}, Duration: time.Second, PacketTimestamp: 5}, 161 {Data: []byte{0x02, 0x03}, Duration: time.Second, PacketTimestamp: 6}, 162 }, 163 maxLate: 50, 164 maxLateTimestamp: 0, 165 }, 166 { 167 message: "SampleBuilder shouldn't emit a packet because we have a gap before a valid one", 168 packets: []*rtp.Packet{ 169 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 170 {Header: rtp.Header{SequenceNumber: 5007, Timestamp: 6}, Payload: []byte{0x02}}, 171 {Header: rtp.Header{SequenceNumber: 5008, Timestamp: 7}, Payload: []byte{0x03}}, 172 }, 173 samples: []*media.Sample{}, 174 maxLate: 50, 175 maxLateTimestamp: 0, 176 }, 177 { 178 message: "SampleBuilder shouldn't emit a packet after a gap as there are gaps and have not reached maxLate yet", 179 packets: []*rtp.Packet{ 180 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 181 {Header: rtp.Header{SequenceNumber: 5007, Timestamp: 6}, Payload: []byte{0x02}}, 182 {Header: rtp.Header{SequenceNumber: 5008, Timestamp: 7}, Payload: []byte{0x03}}, 183 }, 184 withHeadChecker: true, 185 headBytes: []byte{0x02}, 186 samples: []*media.Sample{}, 187 maxLate: 50, 188 maxLateTimestamp: 0, 189 }, 190 { 191 message: "SampleBuilder shouldn't emit a packet after a gap if PartitionHeadChecker doesn't assume it head", 192 packets: []*rtp.Packet{ 193 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 194 {Header: rtp.Header{SequenceNumber: 5007, Timestamp: 6}, Payload: []byte{0x02}}, 195 {Header: rtp.Header{SequenceNumber: 5008, Timestamp: 7}, Payload: []byte{0x03}}, 196 }, 197 withHeadChecker: true, 198 headBytes: []byte{}, 199 samples: []*media.Sample{}, 200 maxLate: 50, 201 maxLateTimestamp: 0, 202 }, 203 { 204 message: "SampleBuilder should emit multiple valid packets", 205 packets: []*rtp.Packet{ 206 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 1}, Payload: []byte{0x01}}, 207 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 2}, Payload: []byte{0x02}}, 208 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 3}, Payload: []byte{0x03}}, 209 {Header: rtp.Header{SequenceNumber: 5003, Timestamp: 4}, Payload: []byte{0x04}}, 210 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 5}, Payload: []byte{0x05}}, 211 {Header: rtp.Header{SequenceNumber: 5005, Timestamp: 6}, Payload: []byte{0x06}}, 212 }, 213 samples: []*media.Sample{ 214 {Data: []byte{0x01}, Duration: time.Second, PacketTimestamp: 1}, 215 {Data: []byte{0x02}, Duration: time.Second, PacketTimestamp: 2}, 216 {Data: []byte{0x03}, Duration: time.Second, PacketTimestamp: 3}, 217 {Data: []byte{0x04}, Duration: time.Second, PacketTimestamp: 4}, 218 {Data: []byte{0x05}, Duration: time.Second, PacketTimestamp: 5}, 219 }, 220 maxLate: 50, 221 maxLateTimestamp: 0, 222 }, 223 { 224 message: "SampleBuilder should skip time stamps too old", 225 packets: []*rtp.Packet{ 226 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 1}, Payload: []byte{0x01}}, 227 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 2}, Payload: []byte{0x02}}, 228 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 3}, Payload: []byte{0x03}}, 229 {Header: rtp.Header{SequenceNumber: 5013, Timestamp: 4000}, Payload: []byte{0x04}}, 230 {Header: rtp.Header{SequenceNumber: 5014, Timestamp: 4000}, Payload: []byte{0x05}}, 231 {Header: rtp.Header{SequenceNumber: 5015, Timestamp: 4002}, Payload: []byte{0x06}}, 232 {Header: rtp.Header{SequenceNumber: 5016, Timestamp: 7000}, Payload: []byte{0x04}}, 233 {Header: rtp.Header{SequenceNumber: 5017, Timestamp: 7001}, Payload: []byte{0x05}}, 234 }, 235 samples: []*media.Sample{ 236 {Data: []byte{0x04, 0x05}, Duration: time.Second * time.Duration(2), PacketTimestamp: 4000, PrevDroppedPackets: 13}, 237 }, 238 withHeadChecker: true, 239 headBytes: []byte{0x04}, 240 maxLate: 50, 241 maxLateTimestamp: 2000, 242 }, 243 { 244 message: "Sample builder should recognize padding packets", 245 packets: []*rtp.Packet{ 246 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 1}, Payload: []byte{1}}, // 1st packet 247 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 1}, Payload: []byte{2}}, // 2nd packet 248 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 1, Marker: true}, Payload: []byte{3}}, // 3rd packet 249 {Header: rtp.Header{SequenceNumber: 5003, Timestamp: 1}, Payload: []byte{}}, // Padding packet 1 250 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 1}, Payload: []byte{}}, // Padding packet 2 251 {Header: rtp.Header{SequenceNumber: 5005, Timestamp: 3}, Payload: []byte{1}}, // 6th packet 252 {Header: rtp.Header{SequenceNumber: 5006, Timestamp: 3, Marker: true}, Payload: []byte{7}}, // 7th packet 253 {Header: rtp.Header{SequenceNumber: 5007, Timestamp: 4}, Payload: []byte{1}}, // 7th packet 254 }, 255 withHeadChecker: true, 256 headBytes: []byte{1}, 257 samples: []*media.Sample{ 258 {Data: []byte{1, 2, 3}, Duration: 0, PacketTimestamp: 1, PrevDroppedPackets: 0}, // first sample 259 }, 260 maxLate: 50, 261 maxLateTimestamp: 2000, 262 }, 263 { 264 message: "Sample builder should build a sample out of a packet that's both start and end following a run of padding packets", 265 packets: []*rtp.Packet{ 266 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 1}, Payload: []byte{1}}, // 1st valid packet 267 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 1, Marker: true}, Payload: []byte{2}}, // 2nd valid packet 268 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 1}, Payload: []byte{}}, // 1st padding packet 269 {Header: rtp.Header{SequenceNumber: 5003, Timestamp: 1}, Payload: []byte{}}, // 2nd padding packet 270 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 2, Marker: true}, Payload: []byte{1}}, // 3rd valid packet 271 {Header: rtp.Header{SequenceNumber: 5005, Timestamp: 3}, Payload: []byte{1}}, // 4th valid packet, start of next sample 272 }, 273 withHeadChecker: true, 274 headBytes: []byte{1}, 275 samples: []*media.Sample{ 276 {Data: []byte{1, 2}, Duration: 0, PacketTimestamp: 1, PrevDroppedPackets: 0}, // 1st sample 277 }, 278 maxLate: 50, 279 maxLateTimestamp: 2000, 280 }, 281 { 282 message: "SampleBuilder should emit samples with RTP headers when WithRTPHeaders option is enabled", 283 packets: []*rtp.Packet{ 284 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 285 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 6}, Payload: []byte{0x02}}, 286 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 6}, Payload: []byte{0x03}}, 287 {Header: rtp.Header{SequenceNumber: 5003, Timestamp: 7}, Payload: []byte{0x04}}, 288 }, 289 samples: []*media.Sample{ 290 {Data: []byte{0x01}, Duration: time.Second, PacketTimestamp: 5, RTPHeaders: []*rtp.Header{ 291 {SequenceNumber: 5000, Timestamp: 5}, 292 }}, 293 {Data: []byte{0x02, 0x03}, Duration: time.Second, PacketTimestamp: 6, RTPHeaders: []*rtp.Header{ 294 {SequenceNumber: 5001, Timestamp: 6}, 295 {SequenceNumber: 5002, Timestamp: 6}, 296 }}, 297 }, 298 maxLate: 50, 299 maxLateTimestamp: 0, 300 withRTPHeader: true, 301 }, 302 } 303 304 t.Run("Pop", func(t *testing.T) { 305 assert := assert.New(t) 306 307 for _, t := range testData { 308 var opts []Option 309 if t.maxLateTimestamp != 0 { 310 opts = append(opts, WithMaxTimeDelay( 311 time.Millisecond*time.Duration(int64(t.maxLateTimestamp)), 312 )) 313 } 314 if t.withRTPHeader { 315 opts = append(opts, WithRTPHeaders(true)) 316 } 317 318 d := &fakeDepacketizer{ 319 headChecker: t.withHeadChecker, 320 headBytes: t.headBytes, 321 } 322 s := New(t.maxLate, d, 1, opts...) 323 samples := []*media.Sample{} 324 325 for _, p := range t.packets { 326 s.Push(p) 327 } 328 for sample := s.Pop(); sample != nil; sample = s.Pop() { 329 samples = append(samples, sample) 330 } 331 assert.Equal(t.samples, samples, t.message) 332 } 333 }) 334 } 335 336 // SampleBuilder should respect maxLate if we popped successfully but then have a gap larger then maxLate 337 func TestSampleBuilderMaxLate(t *testing.T) { 338 assert := assert.New(t) 339 s := New(50, &fakeDepacketizer{}, 1) 340 341 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 0, Timestamp: 1}, Payload: []byte{0x01}}) 342 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 1, Timestamp: 2}, Payload: []byte{0x01}}) 343 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 2, Timestamp: 3}, Payload: []byte{0x01}}) 344 assert.Equal(&media.Sample{Data: []byte{0x01}, Duration: time.Second, PacketTimestamp: 1}, s.Pop(), "Failed to build samples before gap") 345 346 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 5000, Timestamp: 500}, Payload: []byte{0x02}}) 347 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 5001, Timestamp: 501}, Payload: []byte{0x02}}) 348 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 5002, Timestamp: 502}, Payload: []byte{0x02}}) 349 350 assert.Equal(&media.Sample{Data: []byte{0x01}, Duration: time.Second, PacketTimestamp: 2}, s.Pop(), "Failed to build samples after large gap") 351 assert.Equal((*media.Sample)(nil), s.Pop(), "Failed to build samples after large gap") 352 353 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 6000, Timestamp: 600}, Payload: []byte{0x03}}) 354 assert.Equal(&media.Sample{Data: []byte{0x02}, Duration: time.Second, PacketTimestamp: 500, PrevDroppedPackets: 4998}, s.Pop(), "Failed to build samples after large gap") 355 assert.Equal(&media.Sample{Data: []byte{0x02}, Duration: time.Second, PacketTimestamp: 501}, s.Pop(), "Failed to build samples after large gap") 356 } 357 358 func TestSeqnumDistance(t *testing.T) { 359 testData := []struct { 360 x uint16 361 y uint16 362 d uint16 363 }{ 364 {0x0001, 0x0003, 0x0002}, 365 {0x0003, 0x0001, 0x0002}, 366 {0xFFF3, 0xFFF1, 0x0002}, 367 {0xFFF1, 0xFFF3, 0x0002}, 368 {0xFFFF, 0x0001, 0x0002}, 369 {0x0001, 0xFFFF, 0x0002}, 370 } 371 372 for _, data := range testData { 373 if ret := seqnumDistance(data.x, data.y); ret != data.d { 374 t.Errorf("seqnumDistance(%d, %d) returned %d which must be %d", 375 data.x, data.y, ret, data.d) 376 } 377 } 378 } 379 380 func TestSampleBuilderCleanReference(t *testing.T) { 381 for _, seqStart := range []uint16{ 382 0, 383 0xFFF8, // check upper boundary 384 0xFFFE, // check upper boundary 385 } { 386 seqStart := seqStart 387 t.Run(fmt.Sprintf("From%d", seqStart), func(t *testing.T) { 388 s := New(10, &fakeDepacketizer{}, 1) 389 390 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 0 + seqStart, Timestamp: 0}, Payload: []byte{0x01}}) 391 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 1 + seqStart, Timestamp: 0}, Payload: []byte{0x02}}) 392 s.Push(&rtp.Packet{Header: rtp.Header{SequenceNumber: 2 + seqStart, Timestamp: 0}, Payload: []byte{0x03}}) 393 pkt4 := &rtp.Packet{Header: rtp.Header{SequenceNumber: 14 + seqStart, Timestamp: 120}, Payload: []byte{0x04}} 394 s.Push(pkt4) 395 pkt5 := &rtp.Packet{Header: rtp.Header{SequenceNumber: 12 + seqStart, Timestamp: 120}, Payload: []byte{0x05}} 396 s.Push(pkt5) 397 398 for i := 0; i < 3; i++ { 399 if s.buffer[(i+int(seqStart))%0x10000] != nil { 400 t.Errorf("Old packet (%d) is not unreferenced (maxLate: 10, pushed: 12)", i) 401 } 402 } 403 if s.buffer[(14+int(seqStart))%0x10000] != pkt4 { 404 t.Error("New packet must be referenced after jump") 405 } 406 if s.buffer[(12+int(seqStart))%0x10000] != pkt5 { 407 t.Error("New packet must be referenced after jump") 408 } 409 }) 410 } 411 } 412 413 func TestSampleBuilderPushMaxZero(t *testing.T) { 414 // Test packets released via 'maxLate' of zero. 415 pkts := []rtp.Packet{ 416 {Header: rtp.Header{SequenceNumber: 0, Timestamp: 0, Marker: true}, Payload: []byte{0x01}}, 417 } 418 d := &fakeDepacketizer{ 419 headChecker: true, 420 headBytes: []byte{0x01}, 421 } 422 423 s := New(0, d, 1) 424 s.Push(&pkts[0]) 425 if sample := s.Pop(); sample == nil { 426 t.Error("Should expect a popped sample") 427 } 428 } 429 430 func TestSampleBuilderWithPacketReleaseHandler(t *testing.T) { 431 var released []*rtp.Packet 432 fakePacketReleaseHandler := func(p *rtp.Packet) { 433 released = append(released, p) 434 } 435 436 // Test packets released via 'maxLate'. 437 pkts := []rtp.Packet{ 438 {Header: rtp.Header{SequenceNumber: 0, Timestamp: 0}, Payload: []byte{0x01}}, 439 {Header: rtp.Header{SequenceNumber: 11, Timestamp: 120}, Payload: []byte{0x02}}, 440 {Header: rtp.Header{SequenceNumber: 12, Timestamp: 121}, Payload: []byte{0x03}}, 441 {Header: rtp.Header{SequenceNumber: 13, Timestamp: 122}, Payload: []byte{0x04}}, 442 {Header: rtp.Header{SequenceNumber: 21, Timestamp: 200}, Payload: []byte{0x05}}, 443 } 444 s := New(10, &fakeDepacketizer{}, 1, WithPacketReleaseHandler(fakePacketReleaseHandler)) 445 s.Push(&pkts[0]) 446 s.Push(&pkts[1]) 447 if len(released) == 0 { 448 t.Errorf("Old packet is not released") 449 } 450 if len(released) > 0 && released[0].SequenceNumber != pkts[0].SequenceNumber { 451 t.Errorf("Unexpected packet released by maxLate") 452 } 453 // Test packets released after samples built. 454 s.Push(&pkts[2]) 455 s.Push(&pkts[3]) 456 s.Push(&pkts[4]) 457 if s.Pop() == nil { 458 t.Errorf("Should have some sample here.") 459 } 460 if len(released) < 3 { 461 t.Errorf("packet built with sample is not released") 462 } 463 if len(released) >= 2 && released[2].SequenceNumber != pkts[2].SequenceNumber { 464 t.Errorf("Unexpected packet released by samples built") 465 } 466 } 467 468 func TestSampleBuilderWithPacketHeadHandler(t *testing.T) { 469 packets := []*rtp.Packet{ 470 {Header: rtp.Header{SequenceNumber: 5000, Timestamp: 5}, Payload: []byte{0x01}}, 471 {Header: rtp.Header{SequenceNumber: 5001, Timestamp: 5}, Payload: []byte{0x02}}, 472 {Header: rtp.Header{SequenceNumber: 5002, Timestamp: 6}, Payload: []byte{0x01}}, 473 {Header: rtp.Header{SequenceNumber: 5003, Timestamp: 6}, Payload: []byte{0x02}}, 474 {Header: rtp.Header{SequenceNumber: 5004, Timestamp: 7}, Payload: []byte{0x01}}, 475 } 476 477 headCount := 0 478 s := New(10, &fakeDepacketizer{}, 1, WithPacketHeadHandler(func(interface{}) interface{} { 479 headCount++ 480 return true 481 })) 482 483 for _, pkt := range packets { 484 s.Push(pkt) 485 } 486 487 for { 488 sample := s.Pop() 489 if sample == nil { 490 break 491 } 492 493 assert.NotNil(t, sample.Metadata, "sample metadata shouldn't be nil") 494 assert.Equal(t, true, sample.Metadata, "sample metadata should've been set to true") 495 } 496 497 assert.Equal(t, 2, headCount, "two sample heads should have been inspected") 498 } 499 500 func TestSampleBuilderData(t *testing.T) { 501 s := New(10, &fakeDepacketizer{ 502 headChecker: true, 503 alwaysHead: true, 504 }, 1) 505 j := 0 506 for i := 0; i < 0x20000; i++ { 507 p := rtp.Packet{ 508 Header: rtp.Header{ 509 SequenceNumber: uint16(i), 510 Timestamp: uint32(i + 42), 511 }, 512 Payload: []byte{byte(i)}, 513 } 514 s.Push(&p) 515 for { 516 sample := s.Pop() 517 if sample == nil { 518 break 519 } 520 assert.Equal(t, sample.PacketTimestamp, uint32(j+42), "timestamp") 521 assert.Equal(t, len(sample.Data), 1, "data length") 522 assert.Equal(t, byte(j), sample.Data[0], "data") 523 j++ 524 } 525 } 526 // only the last packet should be dropped 527 assert.Equal(t, j, 0x1FFFF) 528 } 529 530 func TestSampleBuilderPacketUnreference(t *testing.T) { 531 s := New(10, &fakeDepacketizer{ 532 headChecker: true, 533 }, 1) 534 535 var refs int64 536 finalizer := func(*rtp.Packet) { 537 atomic.AddInt64(&refs, -1) 538 } 539 540 for i := 0; i < 0x20000; i++ { 541 atomic.AddInt64(&refs, 1) 542 p := rtp.Packet{ 543 Header: rtp.Header{ 544 SequenceNumber: uint16(i), 545 Timestamp: uint32(i + 42), 546 }, 547 Payload: []byte{byte(i)}, 548 } 549 runtime.SetFinalizer(&p, finalizer) 550 s.Push(&p) 551 for { 552 sample := s.Pop() 553 if sample == nil { 554 break 555 } 556 } 557 } 558 559 runtime.GC() 560 time.Sleep(10 * time.Millisecond) 561 562 remainedRefs := atomic.LoadInt64(&refs) 563 runtime.KeepAlive(s) 564 565 // only the last packet should be still referenced 566 assert.Equal(t, int64(1), remainedRefs) 567 } 568 569 func TestSampleBuilder_Flush(t *testing.T) { 570 s := New(50, &fakeDepacketizer{ 571 headChecker: true, 572 headBytes: []byte{0x01}, 573 }, 1) 574 575 s.Push(&rtp.Packet{ 576 Header: rtp.Header{SequenceNumber: 999, Timestamp: 0}, 577 Payload: []byte{0x00}, 578 }) // Invalid packet 579 // Gap preventing below packets to be processed 580 s.Push(&rtp.Packet{ 581 Header: rtp.Header{SequenceNumber: 1001, Timestamp: 1, Marker: true}, 582 Payload: []byte{0x01, 0x11}, 583 }) // Valid packet 584 s.Push(&rtp.Packet{ 585 Header: rtp.Header{SequenceNumber: 1011, Timestamp: 10, Marker: true}, 586 Payload: []byte{0x01, 0x12}, 587 }) // Valid packet 588 589 if sample := s.Pop(); sample != nil { 590 t.Fatal("Unexpected sample is returned. Test precondition may be broken") 591 } 592 593 s.Flush() 594 595 samples := []*media.Sample{} 596 for sample := s.Pop(); sample != nil; sample = s.Pop() { 597 samples = append(samples, sample) 598 } 599 600 expected := []*media.Sample{ 601 {Data: []byte{0x01, 0x11}, Duration: 9 * time.Second, PacketTimestamp: 1, PrevDroppedPackets: 2}, 602 {Data: []byte{0x01, 0x12}, Duration: 0, PacketTimestamp: 10, PrevDroppedPackets: 9}, 603 } 604 605 assert.Equal(t, expected, samples) 606 } 607 608 func BenchmarkSampleBuilderSequential(b *testing.B) { 609 s := New(100, &fakeDepacketizer{}, 1) 610 b.ResetTimer() 611 j := 0 612 for i := 0; i < b.N; i++ { 613 p := rtp.Packet{ 614 Header: rtp.Header{ 615 SequenceNumber: uint16(i), 616 Timestamp: uint32(i + 42), 617 }, 618 Payload: make([]byte, 50), 619 } 620 s.Push(&p) 621 for { 622 s := s.Pop() 623 if s == nil { 624 break 625 } 626 j++ 627 } 628 } 629 if b.N > 200 && j < b.N-100 { 630 b.Errorf("Got %v (N=%v)", j, b.N) 631 } 632 } 633 634 func BenchmarkSampleBuilderLoss(b *testing.B) { 635 s := New(100, &fakeDepacketizer{}, 1) 636 b.ResetTimer() 637 j := 0 638 for i := 0; i < b.N; i++ { 639 if i%13 == 0 { 640 continue 641 } 642 p := rtp.Packet{ 643 Header: rtp.Header{ 644 SequenceNumber: uint16(i), 645 Timestamp: uint32(i + 42), 646 }, 647 Payload: make([]byte, 50), 648 } 649 s.Push(&p) 650 for { 651 s := s.Pop() 652 if s == nil { 653 break 654 } 655 j++ 656 } 657 } 658 if b.N > 200 && j < b.N/2-100 { 659 b.Errorf("Got %v (N=%v)", j, b.N) 660 } 661 } 662 663 func BenchmarkSampleBuilderReordered(b *testing.B) { 664 s := New(100, &fakeDepacketizer{}, 1) 665 b.ResetTimer() 666 j := 0 667 for i := 0; i < b.N; i++ { 668 p := rtp.Packet{ 669 Header: rtp.Header{ 670 SequenceNumber: uint16(i ^ 3), 671 Timestamp: uint32((i ^ 3) + 42), 672 }, 673 Payload: make([]byte, 50), 674 } 675 s.Push(&p) 676 for { 677 s := s.Pop() 678 if s == nil { 679 break 680 } 681 j++ 682 } 683 } 684 if b.N > 2 && j < b.N-5 && j > b.N { 685 b.Errorf("Got %v (N=%v)", j, b.N) 686 } 687 } 688 689 func BenchmarkSampleBuilderFragmented(b *testing.B) { 690 s := New(100, &fakeDepacketizer{}, 1) 691 b.ResetTimer() 692 j := 0 693 for i := 0; i < b.N; i++ { 694 p := rtp.Packet{ 695 Header: rtp.Header{ 696 SequenceNumber: uint16(i), 697 Timestamp: uint32(i/2 + 42), 698 }, 699 Payload: make([]byte, 50), 700 } 701 s.Push(&p) 702 for { 703 s := s.Pop() 704 if s == nil { 705 break 706 } 707 j++ 708 } 709 } 710 if b.N > 200 && j < b.N/2-100 { 711 b.Errorf("Got %v (N=%v)", j, b.N) 712 } 713 } 714 715 func BenchmarkSampleBuilderFragmentedLoss(b *testing.B) { 716 s := New(100, &fakeDepacketizer{}, 1) 717 b.ResetTimer() 718 j := 0 719 for i := 0; i < b.N; i++ { 720 if i%13 == 0 { 721 continue 722 } 723 p := rtp.Packet{ 724 Header: rtp.Header{ 725 SequenceNumber: uint16(i), 726 Timestamp: uint32(i/2 + 42), 727 }, 728 Payload: make([]byte, 50), 729 } 730 s.Push(&p) 731 for { 732 s := s.Pop() 733 if s == nil { 734 break 735 } 736 j++ 737 } 738 } 739 if b.N > 200 && j < b.N/3-100 { 740 b.Errorf("Got %v (N=%v)", j, b.N) 741 } 742 }