Repository: pion/webrtc (Go)

Issue:
Samplebuilder packet loss on RTP sequence number wrap
### Your environment.
  - Version: v3.0.30
  - Browser: N/A
  - Other Information -

### What did you do?

I have pion-to-pion connection which is streaming VP8 video and using the `samplebuilder` to reconstruct the samples.  The sender uses an unaltered `VP8Payloader`, `rtp.Packetizer`, and `rtp.RandomSequencer` though it does set the RTP timestamp in the RTP header using a custom heuristic.

### What did you expect?

During testing over a connection on a local network, I expected the `samplebuilder` not to experience loss when reconstructing samples.  For the most part this is working correctly, however I have noticed that the `samplebuilder` consistently reports packet loss when the RTP sequence number wraps.  

### What happened?

After the sequence number hits 65535, I see it wrap to 0 however I don't see any more samples emitted until it reaches a sequence number of 100 (the configured `maxLate`) after which it emits a sample which reports `PrevDroppedPackets` > 0.  (As an aside, it seems that when the sequence number wraps it can take more than `maxLate` packets for the sample to be emitted as it will be emitted on `maxLate` packets after 0, but this does not include the number of packets received before the wrap.)

As an example, here are some (filtered) logs from my application, `packet` is the RTP header timestamp and `seq` is the RTP sequence number 

```
TRAC[0048] received rtp packet                           codec=video/VP8 len=794 packet=2597305381 seq=65529
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=65530
TRAC[0048] assembled sample                               codec=video/vp8 dropped=0 duration=66.666666ms length=10262 packet=2597305381 timestamp="2021-07-05 19:49:19.599995363 +0000 UTC"      
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=65531
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=65532
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=65533
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=65534
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=65535
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=0
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=1
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=2
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=3
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=4
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597311381 seq=5
TRAC[0048] received rtp packet                           codec=video/VP8 len=1040 packet=2597311381 seq=6
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597317381 seq=7

...

TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597365382 seq=100
TRAC[0048] assembled sample                               codec=video/vp8 dropped=13 duration=66.666666ms length=13031 packet=2597317381 timestamp="2021-07-05 19:49:19.733327363 +0000 UTC"
TRAC[0048] received rtp packet                           codec=video/VP8 len=1188 packet=2597365382 seq=101
```

The sample which is lost (2597311381) is the sample which falls on the sequence number wrap.  The sample for the subsequent timestamp (2597317381) correctly reports 13 dropped packets however it appears that all 13 packets were received in-order (seq 65530-65535 and 0-6).




Discussion:
Please let me know if you have the same issues with https://github.com/jech/samplebuilder




Patch:
diff --git a/pkg/media/samplebuilder/samplebuilder.go b/pkg/media/samplebuilder/samplebuilder.go
index ac3303962d9..8e4ed3ab013 100644
--- a/pkg/media/samplebuilder/samplebuilder.go
+++ b/pkg/media/samplebuilder/samplebuilder.go
@@ -203,7 +203,7 @@ func (s *SampleBuilder) buildSample(purgingBuffers bool) *media.Sample {
 
 	var consume sampleSequenceLocation
 
-	for i := s.active.head; s.buffer[i] != nil && i < s.active.tail; i++ {
+	for i := s.active.head; s.buffer[i] != nil && s.active.compare(i) != slCompareAfter; i++ {
 		if s.depacketizer.IsDetectedFinalPacketInSequence(s.buffer[i].Marker) {
 			consume.head = s.active.head
 			consume.tail = i + 1


Test patch:
diff --git a/pkg/media/samplebuilder/samplebuilder_test.go b/pkg/media/samplebuilder/samplebuilder_test.go
index a5a918a5416..4ca98063eaf 100644
--- a/pkg/media/samplebuilder/samplebuilder_test.go
+++ b/pkg/media/samplebuilder/samplebuilder_test.go
@@ -388,3 +388,38 @@ func TestPopWithTimestamp(t *testing.T) {
 		assert.Equal(t, uint32(0), timestamp)
 	})
 }
+
+type truePartitionHeadChecker struct{}
+
+func (f *truePartitionHeadChecker) IsPartitionHead(payload []byte) bool {
+	return true
+}
+
+func TestSampleBuilderData(t *testing.T) {
+	s := New(10, &fakeDepacketizer{}, 1,
+		WithPartitionHeadChecker(&truePartitionHeadChecker{}),
+	)
+	j := 0
+	for i := 0; i < 0x20000; i++ {
+		p := rtp.Packet{
+			Header: rtp.Header{
+				SequenceNumber: uint16(i),
+				Timestamp:      uint32(i + 42),
+			},
+			Payload: []byte{byte(i)},
+		}
+		s.Push(&p)
+		for {
+			sample, ts := s.PopWithTimestamp()
+			if sample == nil {
+				break
+			}
+			assert.Equal(t, ts, uint32(j+42), "timestamp")
+			assert.Equal(t, len(sample.Data), 1, "data length")
+			assert.Equal(t, byte(j), sample.Data[0], "data")
+			j++
+		}
+	}
+	// only the last packet should be dropped
+	assert.Equal(t, j, 0x1FFFF)
+}