Commit e6bf9338 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Document packetcache.

parent e07a98e3
// Package packetcache implement a packet cache that maintains a history
// of recently seen packets, the last keyframe, and a number of statistics
// that are needed for sending receiver reports.
package packetcache package packetcache
import ( import (
...@@ -5,12 +8,17 @@ import ( ...@@ -5,12 +8,17 @@ import (
"sync" "sync"
) )
const BufSize = 1500 // The maximum size of packets stored in the cache. Chosen to be
// a multiple of 8.
const BufSize = 1504
// The maximum number of packets that constitute a keyframe.
const maxFrame = 1024 const maxFrame = 1024
// entry represents a cached packet.
type entry struct { type entry struct {
seqno uint16 seqno uint16
lengthAndMarker uint16 lengthAndMarker uint16 // 1 bit of marker, 15 bits of length
timestamp uint32 timestamp uint32
buf [BufSize]byte buf [BufSize]byte
} }
...@@ -23,12 +31,14 @@ func (e *entry) marker() bool { ...@@ -23,12 +31,14 @@ func (e *entry) marker() bool {
return (e.lengthAndMarker & 0x8000) != 0 return (e.lengthAndMarker & 0x8000) != 0
} }
// bitmap keeps track of recent loss history
type bitmap struct { type bitmap struct {
valid bool valid bool
first uint16 first uint16
bitmap uint32 bitmap uint32
} }
// frame is used for storing the last keyframe
type frame struct { type frame struct {
timestamp uint32 timestamp uint32
complete bool complete bool
...@@ -53,6 +63,7 @@ type Cache struct { ...@@ -53,6 +63,7 @@ type Cache struct {
entries []entry entries []entry
} }
// New creates a cache with the given capacity.
func New(capacity int) *Cache { func New(capacity int) *Cache {
if capacity > int(^uint16(0)) { if capacity > int(^uint16(0)) {
return nil return nil
...@@ -62,6 +73,7 @@ func New(capacity int) *Cache { ...@@ -62,6 +73,7 @@ func New(capacity int) *Cache {
} }
} }
// compare performs comparison modulo 2^16.
func compare(s1, s2 uint16) int { func compare(s1, s2 uint16) int {
if s1 == s2 { if s1 == s2 {
return 0 return 0
...@@ -72,6 +84,7 @@ func compare(s1, s2 uint16) int { ...@@ -72,6 +84,7 @@ func compare(s1, s2 uint16) int {
return -1 return -1
} }
// seqnoInvalid returns true if seqno is unreasonably far in the past
func seqnoInvalid(seqno, reference uint16) bool { func seqnoInvalid(seqno, reference uint16) bool {
if compare(reference, seqno) < 0 { if compare(reference, seqno) < 0 {
return false return false
...@@ -148,6 +161,7 @@ func (bitmap *bitmap) get(next uint16) (bool, uint16, uint16) { ...@@ -148,6 +161,7 @@ func (bitmap *bitmap) get(next uint16) (bool, uint16, uint16) {
return true, first, uint16(bm >> 1) return true, first, uint16(bm >> 1)
} }
// insert inserts a packet into a frame.
func (frame *frame) insert(seqno uint16, timestamp uint32, marker bool, data []byte) bool { func (frame *frame) insert(seqno uint16, timestamp uint32, marker bool, data []byte) bool {
n := len(frame.entries) n := len(frame.entries)
i := 0 i := 0
...@@ -194,6 +208,8 @@ func (frame *frame) insert(seqno uint16, timestamp uint32, marker bool, data []b ...@@ -194,6 +208,8 @@ func (frame *frame) insert(seqno uint16, timestamp uint32, marker bool, data []b
return true return true
} }
// store checks whether a packet is part of the current keyframe and, if
// so, inserts it.
func (frame *frame) store(seqno uint16, timestamp uint32, first bool, marker bool, data []byte) bool { func (frame *frame) store(seqno uint16, timestamp uint32, first bool, marker bool, data []byte) bool {
if first { if first {
if frame.timestamp != timestamp { if frame.timestamp != timestamp {
...@@ -233,7 +249,8 @@ func (frame *frame) store(seqno uint16, timestamp uint32, first bool, marker boo ...@@ -233,7 +249,8 @@ func (frame *frame) store(seqno uint16, timestamp uint32, first bool, marker boo
return done return done
} }
// Store a packet, setting bitmap at the same time // Store stores a packet in the cache. It returns the first seqno in the
// bitmap, and the index at which the packet was stored.
func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker bool, buf []byte) (uint16, uint16) { func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker bool, buf []byte) (uint16, uint16) {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
...@@ -277,6 +294,7 @@ func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker ...@@ -277,6 +294,7 @@ func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker
return cache.bitmap.first, i return cache.bitmap.first, i
} }
// completeKeyFrame attempts to complete the current keyframe.
func completeKeyframe(cache *Cache) { func completeKeyframe(cache *Cache) {
l := len(cache.keyframe.entries) l := len(cache.keyframe.entries)
if l == 0 { if l == 0 {
...@@ -328,6 +346,7 @@ func completeKeyframe(cache *Cache) { ...@@ -328,6 +346,7 @@ func completeKeyframe(cache *Cache) {
} }
} }
// Expect records that we expect n packets. It is used for loss statistics.
func (cache *Cache) Expect(n int) { func (cache *Cache) Expect(n int) {
if n <= 0 { if n <= 0 {
return return
...@@ -337,6 +356,7 @@ func (cache *Cache) Expect(n int) { ...@@ -337,6 +356,7 @@ func (cache *Cache) Expect(n int) {
cache.expected += uint32(n) cache.expected += uint32(n)
} }
// get retrieves a packet from a slice of entries.
func get(seqno uint16, entries []entry, result []byte) (uint16, uint32, bool) { func get(seqno uint16, entries []entry, result []byte) (uint16, uint32, bool) {
for i := range entries { for i := range entries {
if entries[i].lengthAndMarker == 0 || entries[i].seqno != seqno { if entries[i].lengthAndMarker == 0 || entries[i].seqno != seqno {
...@@ -350,6 +370,7 @@ func get(seqno uint16, entries []entry, result []byte) (uint16, uint32, bool) { ...@@ -350,6 +370,7 @@ func get(seqno uint16, entries []entry, result []byte) (uint16, uint32, bool) {
return 0, 0, false return 0, 0, false
} }
// Get retrieves a packet from the cache.
func (cache *Cache) Get(seqno uint16, result []byte) uint16 { func (cache *Cache) Get(seqno uint16, result []byte) uint16 {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
...@@ -367,6 +388,7 @@ func (cache *Cache) Get(seqno uint16, result []byte) uint16 { ...@@ -367,6 +388,7 @@ func (cache *Cache) Get(seqno uint16, result []byte) uint16 {
return 0 return 0
} }
// GetAt retrieves a packet from the cache assuming it is at the given index.
func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 { func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
...@@ -383,6 +405,8 @@ func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 { ...@@ -383,6 +405,8 @@ func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 {
) )
} }
// Keyframe returns the last buffered keyframe. It returns the frame's
// timestamp and a boolean indicating if the frame is complete.
func (cache *Cache) Keyframe() (uint32, bool, []uint16) { func (cache *Cache) Keyframe() (uint32, bool, []uint16) {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
...@@ -423,6 +447,8 @@ func (cache *Cache) resize(capacity int) { ...@@ -423,6 +447,8 @@ func (cache *Cache) resize(capacity int) {
cache.entries = entries cache.entries = entries
} }
// Resize resizes the cache to the given capacity. This might invalidate
// indices of recently stored packets.
func (cache *Cache) Resize(capacity int) { func (cache *Cache) Resize(capacity int) {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
...@@ -430,6 +456,7 @@ func (cache *Cache) Resize(capacity int) { ...@@ -430,6 +456,7 @@ func (cache *Cache) Resize(capacity int) {
cache.resize(capacity) cache.resize(capacity)
} }
// ResizeCond is like Resize, but avoids invalidating recent indices.
func (cache *Cache) ResizeCond(capacity int) bool { func (cache *Cache) ResizeCond(capacity int) bool {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
...@@ -451,6 +478,8 @@ func (cache *Cache) ResizeCond(capacity int) bool { ...@@ -451,6 +478,8 @@ func (cache *Cache) ResizeCond(capacity int) bool {
return true return true
} }
// GetStats returns statistics about received packets. If reset is true,
// the statistics are reset.
func (cache *Cache) GetStats(reset bool) (uint32, uint32, uint32, uint32) { func (cache *Cache) GetStats(reset bool) (uint32, uint32, uint32, uint32) {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment