diff --git a/pkg/ccfb/duplicate_ack_filter.go b/pkg/ccfb/duplicate_ack_filter.go new file mode 100644 index 00000000..d8ba97c4 --- /dev/null +++ b/pkg/ccfb/duplicate_ack_filter.go @@ -0,0 +1,25 @@ +package ccfb + +type DuplicateAckFilter struct { + highestAckedBySSRC map[uint32]int64 +} + +func NewDuplicateAckFilter() *DuplicateAckFilter { + return &DuplicateAckFilter{ + highestAckedBySSRC: make(map[uint32]int64), + } +} + +func (f *DuplicateAckFilter) Filter(reports Report) { + for ssrc, prs := range reports.SSRCToPacketReports { + n := 0 + for _, report := range prs { + if highest, ok := f.highestAckedBySSRC[ssrc]; !ok || report.SeqNr > highest { + f.highestAckedBySSRC[ssrc] = report.SeqNr + prs[n] = report + n++ + } + } + reports.SSRCToPacketReports[ssrc] = prs[:n] + } +} diff --git a/pkg/ccfb/duplicate_ack_filter_test.go b/pkg/ccfb/duplicate_ack_filter_test.go new file mode 100644 index 00000000..20e4d6f8 --- /dev/null +++ b/pkg/ccfb/duplicate_ack_filter_test.go @@ -0,0 +1,106 @@ +package ccfb + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDuplicateAckFilter(t *testing.T) { + cases := []struct { + in []Report + expect []Report + }{ + { + in: []Report{}, + expect: []Report{}, + }, + { + in: []Report{ + { + SSRCToPacketReports: map[uint32][]PacketReport{ + 0: {}, + }, + }, + }, + expect: []Report{ + { + Arrival: time.Time{}, + Departure: time.Time{}, + SSRCToPacketReports: map[uint32][]PacketReport{ + 0: {}, + }, + }, + }, + }, + { + in: []Report{ + { + SSRCToPacketReports: map[uint32][]PacketReport{ + 0: { + { + SeqNr: 1, + }, + { + SeqNr: 2, + }, + }, + }, + }, + { + SSRCToPacketReports: map[uint32][]PacketReport{ + 0: { + { + SeqNr: 1, + }, + { + SeqNr: 2, + }, + { + SeqNr: 3, + }, + }, + }, + }, + }, + expect: []Report{ + { + Arrival: time.Time{}, + Departure: time.Time{}, + SSRCToPacketReports: map[uint32][]PacketReport{ + 0: { + { + SeqNr: 1, + }, + { + SeqNr: 2, + }, + }, + }, + }, + { + Arrival: time.Time{}, + Departure: time.Time{}, + SSRCToPacketReports: map[uint32][]PacketReport{ + 0: { + { + SeqNr: 3, + }, + }, + }, + }, + }, + }, + } + for i, tc := range cases { + t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { + daf := NewDuplicateAckFilter() + for i, m := range tc.in { + daf.Filter(m) + assert.Equal(t, tc.expect[i], m) + } + }) + } +}