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  }