From 48f8054cdfeadfed68b8b66fb5434de598285416 Mon Sep 17 00:00:00 2001 From: Mathis Engelbart Date: Mon, 27 Jan 2025 11:11:29 +0100 Subject: [PATCH] Simplify report result types --- pkg/ccfb/ccfb_receiver.go | 18 ++--- pkg/ccfb/ccfb_receiver_test.go | 131 +++++++++++++++------------------ pkg/ccfb/history.go | 18 +---- pkg/ccfb/history_test.go | 43 +++++------ pkg/ccfb/interceptor.go | 35 ++++++--- pkg/ccfb/interceptor_test.go | 102 +++++++++++-------------- pkg/ccfb/twcc_receiver.go | 9 +-- pkg/ccfb/twcc_receiver_test.go | 56 +++++++------- 8 files changed, 178 insertions(+), 234 deletions(-) diff --git a/pkg/ccfb/ccfb_receiver.go b/pkg/ccfb/ccfb_receiver.go index a90a9e9b..a2c3e567 100644 --- a/pkg/ccfb/ccfb_receiver.go +++ b/pkg/ccfb/ccfb_receiver.go @@ -14,24 +14,19 @@ type acknowledgement struct { ecn rtcp.ECN } -type acknowledgementList struct { - ts time.Time - acks []acknowledgement -} - -func convertCCFB(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32]acknowledgementList) { +func convertCCFB(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32][]acknowledgement) { if feedback == nil { return time.Time{}, nil } - result := map[uint32]acknowledgementList{} + result := map[uint32][]acknowledgement{} referenceTime := ntp.ToTime32(feedback.ReportTimestamp, ts) for _, rb := range feedback.ReportBlocks { - result[rb.MediaSSRC] = convertMetricBlock(ts, referenceTime, rb.BeginSequence, rb.MetricBlocks) + result[rb.MediaSSRC] = convertMetricBlock(referenceTime, rb.BeginSequence, rb.MetricBlocks) } return referenceTime, result } -func convertMetricBlock(ts time.Time, reference time.Time, seqNrOffset uint16, blocks []rtcp.CCFeedbackMetricBlock) acknowledgementList { +func convertMetricBlock(reference time.Time, seqNrOffset uint16, blocks []rtcp.CCFeedbackMetricBlock) []acknowledgement { reports := make([]acknowledgement, len(blocks)) for i, mb := range blocks { if mb.Received { @@ -60,8 +55,5 @@ func convertMetricBlock(ts time.Time, reference time.Time, seqNrOffset uint16, b } } } - return acknowledgementList{ - ts: ts, - acks: reports, - } + return reports } diff --git a/pkg/ccfb/ccfb_receiver_test.go b/pkg/ccfb/ccfb_receiver_test.go index 936a6e9d..6aed3a08 100644 --- a/pkg/ccfb/ccfb_receiver_test.go +++ b/pkg/ccfb/ccfb_receiver_test.go @@ -15,7 +15,7 @@ func TestConvertCCFB(t *testing.T) { cases := []struct { ts time.Time feedback *rtcp.CCFeedbackReport - expect map[uint32]acknowledgementList + expect map[uint32][]acknowledgement expectTS time.Time }{ {}, @@ -38,16 +38,13 @@ func TestConvertCCFB(t *testing.T) { }, ReportTimestamp: ntp.ToNTP32(timeZero.Add(time.Second)), }, - expect: map[uint32]acknowledgementList{ - 2: { - ts: timeZero.Add(2 * time.Second), - acks: []acknowledgement{ - { - seqNr: 17, - arrived: true, - arrival: timeZero.Add(500 * time.Millisecond), - ecn: 0, - }, + expect: map[uint32][]acknowledgement{ + 2: []acknowledgement{ + { + seqNr: 17, + arrived: true, + arrival: timeZero.Add(500 * time.Millisecond), + ecn: 0, }, }, }, @@ -63,13 +60,12 @@ func TestConvertCCFB(t *testing.T) { // Can't directly check equality since arrival timestamp conversions // may be slightly off due to ntp conversions. assert.Equal(t, len(tc.expect), len(res)) - for i, ee := range tc.expect { - assert.Equal(t, ee.ts, res[i].ts) - for j, ack := range ee.acks { - assert.Equal(t, ack.seqNr, res[i].acks[j].seqNr) - assert.Equal(t, ack.arrived, res[i].acks[j].arrived) - assert.Equal(t, ack.ecn, res[i].acks[j].ecn) - assert.InDelta(t, ack.arrival.UnixNano(), res[i].acks[j].arrival.UnixNano(), float64(time.Millisecond.Nanoseconds())) + for i, acks := range tc.expect { + for j, ack := range acks { + assert.Equal(t, ack.seqNr, res[i][j].seqNr) + assert.Equal(t, ack.arrived, res[i][j].arrived) + assert.Equal(t, ack.ecn, res[i][j].ecn) + assert.InDelta(t, ack.arrival.UnixNano(), res[i][j].arrival.UnixNano(), float64(time.Millisecond.Nanoseconds())) } } }) @@ -82,17 +78,14 @@ func TestConvertMetricBlock(t *testing.T) { reference time.Time seqNrOffset uint16 blocks []rtcp.CCFeedbackMetricBlock - expected acknowledgementList + expected []acknowledgement }{ { ts: time.Time{}, reference: time.Time{}, seqNrOffset: 0, blocks: []rtcp.CCFeedbackMetricBlock{}, - expected: acknowledgementList{ - ts: time.Time{}, - acks: []acknowledgement{}, - }, + expected: []acknowledgement{}, }, { ts: time.Time{}.Add(2 * time.Second), @@ -115,27 +108,24 @@ func TestConvertMetricBlock(t *testing.T) { ArrivalTimeOffset: 0, }, }, - expected: acknowledgementList{ - ts: time.Time{}.Add(2 * time.Second), - acks: []acknowledgement{ - { - seqNr: 3, - arrived: true, - arrival: time.Time{}.Add(500 * time.Millisecond), - ecn: 0, - }, - { - seqNr: 4, - arrived: false, - arrival: time.Time{}, - ecn: 0, - }, - { - seqNr: 5, - arrived: true, - arrival: time.Time{}.Add(time.Second), - ecn: 0, - }, + expected: []acknowledgement{ + { + seqNr: 3, + arrived: true, + arrival: time.Time{}.Add(500 * time.Millisecond), + ecn: 0, + }, + { + seqNr: 4, + arrived: false, + arrival: time.Time{}, + ecn: 0, + }, + { + seqNr: 5, + arrived: true, + arrival: time.Time{}.Add(time.Second), + ecn: 0, }, }, }, @@ -165,33 +155,30 @@ func TestConvertMetricBlock(t *testing.T) { ArrivalTimeOffset: 0x1FFF, }, }, - expected: acknowledgementList{ - ts: time.Time{}.Add(2 * time.Second), - acks: []acknowledgement{ - { - seqNr: 3, - arrived: true, - arrival: time.Time{}.Add(500 * time.Millisecond), - ecn: 0, - }, - { - seqNr: 4, - arrived: false, - arrival: time.Time{}, - ecn: 0, - }, - { - seqNr: 5, - arrived: true, - arrival: time.Time{}.Add(time.Second), - ecn: 0, - }, - { - seqNr: 6, - arrived: true, - arrival: time.Time{}, - ecn: 0, - }, + expected: []acknowledgement{ + { + seqNr: 3, + arrived: true, + arrival: time.Time{}.Add(500 * time.Millisecond), + ecn: 0, + }, + { + seqNr: 4, + arrived: false, + arrival: time.Time{}, + ecn: 0, + }, + { + seqNr: 5, + arrived: true, + arrival: time.Time{}.Add(time.Second), + ecn: 0, + }, + { + seqNr: 6, + arrived: true, + arrival: time.Time{}, + ecn: 0, }, }, }, @@ -199,7 +186,7 @@ func TestConvertMetricBlock(t *testing.T) { for i, tc := range cases { t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { - res := convertMetricBlock(tc.ts, tc.reference, tc.seqNrOffset, tc.blocks) + res := convertMetricBlock(tc.reference, tc.seqNrOffset, tc.blocks) assert.Equal(t, tc.expected, res) }) } diff --git a/pkg/ccfb/history.go b/pkg/ccfb/history.go index e95f9215..fde4c6d6 100644 --- a/pkg/ccfb/history.go +++ b/pkg/ccfb/history.go @@ -10,12 +10,6 @@ import ( "github.com/pion/rtcp" ) -type PacketReportList struct { - Arrival time.Time - Departure time.Time - Reports []PacketReport -} - type PacketReport struct { SeqNr int64 Size uint16 @@ -85,12 +79,12 @@ func (h *historyList) removeOldest() { } } -func (h *historyList) getReportForAck(al acknowledgementList) PacketReportList { +func (h *historyList) getReportForAck(acks []acknowledgement) []PacketReport { h.lock.Lock() defer h.lock.Unlock() - var reports []PacketReport - for _, pr := range al.acks { + reports := []PacketReport{} + for _, pr := range acks { sn := h.ackedSeqNr.Unwrap(pr.seqNr) ent, ok := h.seqNrToPacket[sn] // Ignore report for unknown packets (migth have been dropped from @@ -108,9 +102,5 @@ func (h *historyList) getReportForAck(al acknowledgementList) PacketReportList { } } } - - return PacketReportList{ - Arrival: al.ts, - Reports: reports, - } + return reports } diff --git a/pkg/ccfb/history_test.go b/pkg/ccfb/history_test.go index 2762e56f..725b7ca2 100644 --- a/pkg/ccfb/history_test.go +++ b/pkg/ccfb/history_test.go @@ -23,8 +23,8 @@ func TestHistory(t *testing.T) { size uint16 ts time.Time } - acks acknowledgementList - expectedReport PacketReportList + acks []acknowledgement + expectedReport []PacketReport expectedHistorySize int }{ { @@ -33,8 +33,8 @@ func TestHistory(t *testing.T) { size uint16 ts time.Time }{}, - acks: acknowledgementList{}, - expectedReport: PacketReportList{}, + acks: []acknowledgement{}, + expectedReport: []PacketReport{}, expectedHistorySize: 0, }, { @@ -48,8 +48,8 @@ func TestHistory(t *testing.T) { {2, 1200, time.Time{}.Add(3 * time.Millisecond)}, {3, 1200, time.Time{}.Add(4 * time.Millisecond)}, }, - acks: acknowledgementList{}, - expectedReport: PacketReportList{}, + acks: []acknowledgement{}, + expectedReport: []PacketReport{}, expectedHistorySize: 4, }, { @@ -63,21 +63,15 @@ func TestHistory(t *testing.T) { {2, 1200, time.Time{}.Add(3 * time.Millisecond)}, {3, 1200, time.Time{}.Add(4 * time.Millisecond)}, }, - acks: acknowledgementList{ - ts: time.Time{}.Add(time.Second), - acks: []acknowledgement{ - {1, true, time.Time{}.Add(3 * time.Millisecond), 0}, - {2, false, time.Time{}, 0}, - {3, true, time.Time{}.Add(5 * time.Millisecond), 0}, - }, + acks: []acknowledgement{ + {1, true, time.Time{}.Add(3 * time.Millisecond), 0}, + {2, false, time.Time{}, 0}, + {3, true, time.Time{}.Add(5 * time.Millisecond), 0}, }, - expectedReport: PacketReportList{ - Arrival: time.Time{}.Add(time.Second), - Reports: []PacketReport{ - {1, 1200, time.Time{}.Add(2 * time.Millisecond), true, time.Time{}.Add(3 * time.Millisecond), 0}, - {2, 1200, time.Time{}.Add(3 * time.Millisecond), false, time.Time{}, 0}, - {3, 1200, time.Time{}.Add(4 * time.Millisecond), true, time.Time{}.Add(5 * time.Millisecond), 0}, - }, + expectedReport: []PacketReport{ + {1, 1200, time.Time{}.Add(2 * time.Millisecond), true, time.Time{}.Add(3 * time.Millisecond), 0}, + {2, 1200, time.Time{}.Add(3 * time.Millisecond), false, time.Time{}, 0}, + {3, 1200, time.Time{}.Add(4 * time.Millisecond), true, time.Time{}.Add(5 * time.Millisecond), 0}, }, expectedHistorySize: 4, }, @@ -103,12 +97,9 @@ func TestHistory(t *testing.T) { assert.NoError(t, h.add(i, 1200, time.Time{}.Add(time.Duration(i)*time.Millisecond))) } - acks := acknowledgementList{ - ts: time.Time{}.Add(time.Second), - acks: []acknowledgement{}, - } + acks := []acknowledgement{} for i := uint16(200); i < 290; i++ { - acks.acks = append(acks.acks, acknowledgement{ + acks = append(acks, acknowledgement{ seqNr: i, arrived: true, arrival: time.Time{}.Add(time.Duration(500+i) * time.Millisecond), @@ -116,7 +107,7 @@ func TestHistory(t *testing.T) { }) } prl := h.getReportForAck(acks) - assert.Len(t, prl.Reports, 90) + assert.Len(t, prl, 90) assert.Equal(t, 200, len(h.seqNrToPacket)) assert.Equal(t, 200, h.evictList.Len()) }) diff --git a/pkg/ccfb/interceptor.go b/pkg/ccfb/interceptor.go index df763881..66c0ffe3 100644 --- a/pkg/ccfb/interceptor.go +++ b/pkg/ccfb/interceptor.go @@ -15,9 +15,15 @@ type ccfbAttributesKeyType uint32 const CCFBAttributesKey ccfbAttributesKeyType = iota +type Report struct { + Arrival time.Time + Departure time.Time + SSRCToPacketReports map[uint32][]PacketReport +} + type history interface { add(seqNr uint16, size uint16, departure time.Time) error - getReportForAck(al acknowledgementList) PacketReportList + getReportForAck([]acknowledgement) []PacketReport } type Option func(*Interceptor) error @@ -43,14 +49,14 @@ func historyFactory(f func(int) history) Option { } } -func ccfbConverterFactory(f func(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32]acknowledgementList)) Option { +func ccfbConverterFactory(f func(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32][]acknowledgement)) Option { return func(i *Interceptor) error { i.convertCCFB = f return nil } } -func twccConverterFactory(f func(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32]acknowledgementList)) Option { +func twccConverterFactory(f func(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32][]acknowledgement)) Option { return func(i *Interceptor) error { i.convertTWCC = f return nil @@ -92,8 +98,8 @@ type Interceptor struct { interceptor.NoOp lock sync.Mutex timestamp func() time.Time - convertCCFB func(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32]acknowledgementList) - convertTWCC func(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32]acknowledgementList) + convertCCFB func(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32][]acknowledgement) + convertTWCC func(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32][]acknowledgement) ssrcToHistory map[uint32]history historySize int historyFactory func(int) history @@ -157,14 +163,14 @@ func (i *Interceptor) BindRTCPReader(reader interceptor.RTCPReader) interceptor. attr = make(interceptor.Attributes) } - pktReportLists := map[uint32]*PacketReportList{} + res := []Report{} pkts, err := attr.GetRTCPPackets(buf) if err != nil { return n, attr, err } for _, pkt := range pkts { - var reportLists map[uint32]acknowledgementList + var reportLists map[uint32][]acknowledgement var reportDeparture time.Time switch fb := pkt.(type) { case *rtcp.CCFeedbackReport: @@ -173,17 +179,22 @@ func (i *Interceptor) BindRTCPReader(reader interceptor.RTCPReader) interceptor. reportDeparture, reportLists = i.convertTWCC(now, fb) default: } + ssrcToPrl := map[uint32][]PacketReport{} for ssrc, reportList := range reportLists { prl := i.ssrcToHistory[ssrc].getReportForAck(reportList) - prl.Departure = reportDeparture - if l, ok := pktReportLists[ssrc]; !ok { - pktReportLists[ssrc] = &prl + if l, ok := ssrcToPrl[ssrc]; !ok { + ssrcToPrl[ssrc] = prl } else { - l.Reports = append(l.Reports, prl.Reports...) + l = append(l, prl...) } } + res = append(res, Report{ + Arrival: now, + Departure: reportDeparture, + SSRCToPacketReports: ssrcToPrl, + }) } - attr.Set(CCFBAttributesKey, pktReportLists) + attr.Set(CCFBAttributesKey, res) return n, attr, err }) } diff --git a/pkg/ccfb/interceptor_test.go b/pkg/ccfb/interceptor_test.go index 98946200..cd53d781 100644 --- a/pkg/ccfb/interceptor_test.go +++ b/pkg/ccfb/interceptor_test.go @@ -20,7 +20,7 @@ type mockHistoryAddEntry struct { type mockHistory struct { added []mockHistoryAddEntry - report PacketReportList + report []PacketReport } // add implements history. @@ -34,7 +34,7 @@ func (m *mockHistory) add(seqNr uint16, size uint16, departure time.Time) error } // getReportForAck implements history. -func (m *mockHistory) getReportForAck(_ acknowledgementList) PacketReportList { +func (m *mockHistory) getReportForAck(_ []acknowledgement) []PacketReport { return m.report } @@ -142,43 +142,31 @@ func TestInterceptor(t *testing.T) { mh *mockHistory rtcp rtcp.Packet }{ - //{ - // mh: &mockHistory{ - // report: PacketReportList{ - // Arrival: mockTimestamp, - // Departure: mockTimestamp, - // Reports: []PacketReport{}, - // }, - // }, - // rtcp: &rtcp.CCFeedbackReport{}, - //}, - //{ - // mh: &mockHistory{ - // report: PacketReportList{ - // Arrival: mockTimestamp, - // Departure: mockTimestamp, - // Reports: []PacketReport{ - // { - // SeqNr: 3, - // Size: 12, - // Departure: mockTimestamp, - // Arrived: true, - // Arrival: mockTimestamp, - // ECN: 0, - // }, - // }, - // }, - // }, - // rtcp: &rtcp.CCFeedbackReport{}, - //}, { mh: &mockHistory{ - report: PacketReportList{ - Arrival: mockTimestamp, - Departure: mockTimestamp, - Reports: []PacketReport{}, + report: []PacketReport{}, + }, + rtcp: &rtcp.CCFeedbackReport{}, + }, + { + mh: &mockHistory{ + report: []PacketReport{ + { + SeqNr: 3, + Size: 12, + Departure: mockTimestamp, + Arrived: true, + Arrival: mockTimestamp, + ECN: 0, + }, }, }, + rtcp: &rtcp.CCFeedbackReport{}, + }, + { + mh: &mockHistory{ + report: []PacketReport{}, + }, rtcp: &rtcp.TransportLayerCC{ Header: rtcp.Header{ Padding: false, @@ -208,18 +196,14 @@ func TestInterceptor(t *testing.T) { }, { mh: &mockHistory{ - report: PacketReportList{ - Arrival: mockTimestamp, - Departure: mockTimestamp, - Reports: []PacketReport{ - { - SeqNr: 3, - Size: 12, - Departure: mockTimestamp, - Arrived: true, - Arrival: mockTimestamp, - ECN: 0, - }, + report: []PacketReport{ + { + SeqNr: 3, + Size: 12, + Departure: mockTimestamp, + Arrived: true, + Arrival: mockTimestamp, + ECN: 0, }, }, }, @@ -256,13 +240,13 @@ func TestInterceptor(t *testing.T) { mt := func() time.Time { return mockTimestamp } - mockCCFBConverter := func(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32]acknowledgementList) { - return mockTimestamp, map[uint32]acknowledgementList{ + mockCCFBConverter := func(ts time.Time, feedback *rtcp.CCFeedbackReport) (time.Time, map[uint32][]acknowledgement) { + return mockTimestamp, map[uint32][]acknowledgement{ 0: {}, } } - mockTWCCConverter := func(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32]acknowledgementList) { - return mockTimestamp, map[uint32]acknowledgementList{ + mockTWCCConverter := func(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32][]acknowledgement) { + return mockTimestamp, map[uint32][]acknowledgement{ 0: {}, } } @@ -280,12 +264,12 @@ func TestInterceptor(t *testing.T) { assert.NoError(t, err) info := &interceptor.StreamInfo{} - // if _, ok := tc.rtcp.(*rtcp.TransportLayerCC); ok { - // info.RTPHeaderExtensions = append(info.RTPHeaderExtensions, interceptor.RTPHeaderExtension{ - // URI: transportCCURI, - // ID: 2, - // }) - // } + if _, ok := tc.rtcp.(*rtcp.TransportLayerCC); ok { + info.RTPHeaderExtensions = append(info.RTPHeaderExtensions, interceptor.RTPHeaderExtension{ + URI: transportCCURI, + ID: 2, + }) + } stream := test.NewMockStream(info, i) stream.ReceiveRTCP([]rtcp.Packet{tc.rtcp}) @@ -296,10 +280,10 @@ func TestInterceptor(t *testing.T) { prlsInterface, ok := report.Attr[CCFBAttributesKey] assert.True(t, ok) - prls, ok := prlsInterface.(map[uint32]*PacketReportList) + prls, ok := prlsInterface.([]Report) assert.True(t, ok) assert.Len(t, prls, 1) - // assert.Equal(t, tc.mh.report, *prls[0]) + assert.Equal(t, tc.mh.report, prls[0].SSRCToPacketReports[0]) }) } }) diff --git a/pkg/ccfb/twcc_receiver.go b/pkg/ccfb/twcc_receiver.go index 31c3d2c8..ebbce5c8 100644 --- a/pkg/ccfb/twcc_receiver.go +++ b/pkg/ccfb/twcc_receiver.go @@ -6,7 +6,7 @@ import ( "github.com/pion/rtcp" ) -func convertTWCC(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32]acknowledgementList) { +func convertTWCC(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[uint32][]acknowledgement) { if feedback == nil { return time.Time{}, nil } @@ -84,10 +84,5 @@ func convertTWCC(ts time.Time, feedback *rtcp.TransportLayerCC) (time.Time, map[ } } - return reportDeparture, map[uint32]acknowledgementList{ - 0: { - ts: ts, - acks: acks, - }, - } + return reportDeparture, map[uint32][]acknowledgement{0: acks} } diff --git a/pkg/ccfb/twcc_receiver_test.go b/pkg/ccfb/twcc_receiver_test.go index 76d0dd03..55da3548 100644 --- a/pkg/ccfb/twcc_receiver_test.go +++ b/pkg/ccfb/twcc_receiver_test.go @@ -14,7 +14,7 @@ func TestConvertTWCC(t *testing.T) { cases := []struct { ts time.Time feedback *rtcp.TransportLayerCC - expect map[uint32]acknowledgementList + expect map[uint32][]acknowledgement expectTS time.Time }{ {}, @@ -30,11 +30,8 @@ func TestConvertTWCC(t *testing.T) { PacketChunks: []rtcp.PacketStatusChunk{}, RecvDeltas: []*rtcp.RecvDelta{}, }, - expect: map[uint32]acknowledgementList{ - 0: { - ts: timeZero.Add(2 * time.Second), - acks: nil, - }, + expect: map[uint32][]acknowledgement{ + 0: nil, }, expectTS: time.Time{}.Add(3 * 64 * time.Millisecond), }, @@ -89,34 +86,31 @@ func TestConvertTWCC(t *testing.T) { {Type: rtcp.TypeTCCPacketReceivedLargeDelta, Delta: 1000}, }, }, - expect: map[uint32]acknowledgementList{ + expect: map[uint32][]acknowledgement{ 0: { - ts: timeZero.Add(2 * time.Second), - acks: []acknowledgement{ - // first run length chunk - {seqNr: 178, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 1*time.Millisecond), ecn: 0}, - {seqNr: 179, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 2*time.Millisecond), ecn: 0}, - {seqNr: 180, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 3*time.Millisecond), ecn: 0}, + // first run length chunk + {seqNr: 178, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 1*time.Millisecond), ecn: 0}, + {seqNr: 179, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 2*time.Millisecond), ecn: 0}, + {seqNr: 180, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 3*time.Millisecond), ecn: 0}, - // first status vector chunk - {seqNr: 181, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 4*time.Millisecond), ecn: 0}, - {seqNr: 182, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 5*time.Millisecond), ecn: 0}, - {seqNr: 183, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 6*time.Millisecond), ecn: 0}, - {seqNr: 184, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 185, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 186, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 187, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 188, arrived: false, arrival: time.Time{}, ecn: 0}, + // first status vector chunk + {seqNr: 181, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 4*time.Millisecond), ecn: 0}, + {seqNr: 182, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 5*time.Millisecond), ecn: 0}, + {seqNr: 183, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 6*time.Millisecond), ecn: 0}, + {seqNr: 184, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 185, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 186, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 187, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 188, arrived: false, arrival: time.Time{}, ecn: 0}, - // second status vector chunk - {seqNr: 189, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 7*time.Millisecond), ecn: 0}, - {seqNr: 190, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 8*time.Millisecond), ecn: 0}, - {seqNr: 191, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 192, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 193, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 194, arrived: false, arrival: time.Time{}, ecn: 0}, - {seqNr: 195, arrived: false, arrival: time.Time{}, ecn: 0}, - }, + // second status vector chunk + {seqNr: 189, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 7*time.Millisecond), ecn: 0}, + {seqNr: 190, arrived: true, arrival: time.Time{}.Add(3*64*time.Millisecond + 8*time.Millisecond), ecn: 0}, + {seqNr: 191, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 192, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 193, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 194, arrived: false, arrival: time.Time{}, ecn: 0}, + {seqNr: 195, arrived: false, arrival: time.Time{}, ecn: 0}, }, }, expectTS: time.Time{}.Add(3 * 64 * time.Millisecond),