diff --git a/packetcache/packetcache.go b/packetcache/packetcache.go index 309b07a..d48eb33 100644 --- a/packetcache/packetcache.go +++ b/packetcache/packetcache.go @@ -526,3 +526,21 @@ func (cache *Cache) GetStats(reset bool) (uint32, uint32, uint32, uint32) { } return expected, lost, totalLost, eseqno } + +// ToBitmap takes a non-empty sorted list of seqnos, and computes a bitmap +// covering a prefix of the list. It returns the part of the list that +// couldn't be covered. +func ToBitmap(seqnos []uint16) (first uint16, bitmap uint16, remain []uint16) { + first = seqnos[0] + bitmap = uint16(0) + remain = seqnos[1:] + for len(remain) > 0 { + delta := remain[0] - first - 1 + if delta >= 16 { + break + } + bitmap = bitmap | (1 << delta) + remain = remain[1:] + } + return +} diff --git a/packetcache/packetcache_test.go b/packetcache/packetcache_test.go index 7f87163..c6bd7f3 100644 --- a/packetcache/packetcache_test.go +++ b/packetcache/packetcache_test.go @@ -3,6 +3,7 @@ package packetcache import ( "bytes" "math/rand" + "reflect" "sync" "testing" @@ -457,3 +458,39 @@ func BenchmarkCachePutGetAt(b *testing.B) { } wg.Wait() } + +func TestToBitmap(t *testing.T) { + l := []uint16{18, 19, 32, 38} + bb := uint16(1 | 1<<(32-18-1)) + f, b, r := ToBitmap(l) + if f != 18 || b != bb { + t.Errorf("Expected %v %v, Got %v %v", 18, bb, f, b) + } + if len(r) != 1 || r[0] != 38 { + t.Errorf("Expected [38], got %v", r) + } + + f2, b2, r2 := ToBitmap(r) + if f2 != 38 || b2 != 0 || len(r2) != 0 { + t.Errorf("Expected 38 0, got %v %v %v", f2, b2, r2) + } +} + +func TestToBitmapNack(t *testing.T) { + l := []uint16{18, 19, 32, 38} + var nacks []rtcp.NackPair + m := l + for len(m) > 0 { + var f, b uint16 + f, b, m = ToBitmap(m) + nacks = append(nacks, rtcp.NackPair{f, rtcp.PacketBitmap(b)}) + } + var n []uint16 + for len(nacks) > 0 { + n = append(n, nacks[0].PacketList()...) + nacks = nacks[1:] + } + if !reflect.DeepEqual(l, n) { + t.Errorf("Expected %v, got %v", l, n) + } +}