Files
livekit/pkg/sfu/videolayerselector/selectordecisioncache.go
T
David Zhao 981fb7cac7 Adding license notices (#1913)
* Adding license notices

* remove from config
2023-07-27 16:43:19 -07:00

198 lines
5.0 KiB
Go

// Copyright 2023 LiveKit, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package videolayerselector
import (
"fmt"
)
// ----------------------------------------------------------------------
type selectorDecision int
const (
selectorDecisionMissing selectorDecision = iota
selectorDecisionDropped
selectorDecisionForwarded
selectorDecisionUnknown
)
func (s selectorDecision) String() string {
switch s {
case selectorDecisionMissing:
return "MISSING"
case selectorDecisionDropped:
return "DROPPED"
case selectorDecisionForwarded:
return "FORWARDED"
case selectorDecisionUnknown:
return "UNKNOWN"
default:
return fmt.Sprintf("%d", int(s))
}
}
// ----------------------------------------------------------------------
type SelectorDecisionCache struct {
initialized bool
base uint64
last uint64
masks []uint64
numEntries uint64
numNackEntries uint64
onExpectEntityChanged map[uint64][]func(entity uint64, decision selectorDecision)
}
func NewSelectorDecisionCache(maxNumElements uint64, numNackEntries uint64) *SelectorDecisionCache {
numElements := (maxNumElements*2 + 63) / 64
return &SelectorDecisionCache{
masks: make([]uint64, numElements),
numEntries: numElements * 32, // 2 bits per entry
numNackEntries: numNackEntries,
onExpectEntityChanged: make(map[uint64][]func(entity uint64, decision selectorDecision)),
}
}
func (s *SelectorDecisionCache) AddForwarded(entity uint64) {
s.addEntity(entity, selectorDecisionForwarded)
}
func (s *SelectorDecisionCache) AddDropped(entity uint64) {
s.addEntity(entity, selectorDecisionDropped)
}
func (s *SelectorDecisionCache) GetDecision(entity uint64) (selectorDecision, error) {
if !s.initialized || entity < s.base {
return selectorDecisionMissing, nil
}
if entity > s.last {
return selectorDecisionUnknown, nil
}
offset := s.last - entity
if offset >= s.numEntries {
// asking for something too old
return selectorDecisionMissing, fmt.Errorf("too old, oldest: %d, asking: %d", s.last-s.numEntries+1, entity)
}
return s.getEntity(entity), nil
}
func (s *SelectorDecisionCache) ExpectDecision(entity uint64, f func(entity uint64, decision selectorDecision)) bool {
if !s.initialized || entity < s.base {
return false
}
if entity < s.last {
offset := s.last - entity
if offset >= s.numEntries {
return false // too old
}
}
s.onExpectEntityChanged[entity] = append(s.onExpectEntityChanged[entity], f)
return true
}
func (s *SelectorDecisionCache) addEntity(entity uint64, sd selectorDecision) {
if !s.initialized {
s.initialized = true
s.base = entity
s.last = entity
s.setEntity(entity, sd)
return
}
if entity <= s.base {
// before base, too old
return
}
if entity <= s.last {
s.setEntity(entity, sd)
return
}
for e := s.last + 1; e != entity; e++ {
s.setEntity(e, selectorDecisionUnknown)
}
// update [last+1-nack, entity-nack) to missing
missingStart := s.last
if missingStart > s.numNackEntries+s.base {
missingStart -= s.numNackEntries
} else {
missingStart = s.base
}
missingEnd := entity
if missingEnd > s.numNackEntries+s.base {
missingEnd -= s.numNackEntries
} else {
missingEnd = s.base
}
if missingEnd > missingStart {
for e := missingStart; e != missingEnd; e++ {
s.setEntityIfUnknown(e, selectorDecisionMissing)
}
}
s.setEntity(entity, sd)
s.last = entity
for e, fns := range s.onExpectEntityChanged {
if e+s.numEntries < s.last {
delete(s.onExpectEntityChanged, e)
for _, f := range fns {
f(e, selectorDecisionMissing)
}
}
}
}
func (s *SelectorDecisionCache) setEntityIfUnknown(entity uint64, sd selectorDecision) {
if s.getEntity(entity) == selectorDecisionUnknown {
s.setEntity(entity, sd)
}
}
func (s *SelectorDecisionCache) setEntity(entity uint64, sd selectorDecision) {
index, bitpos := s.getPos(entity)
s.masks[index] &= ^(0x3 << bitpos) // clear before bitwise OR
s.masks[index] |= (uint64(sd) & 0x3) << bitpos
if sd != selectorDecisionUnknown {
if fns, ok := s.onExpectEntityChanged[entity]; ok {
delete(s.onExpectEntityChanged, entity)
for _, f := range fns {
f(entity, sd)
}
}
}
}
func (s *SelectorDecisionCache) getEntity(entity uint64) selectorDecision {
index, bitpos := s.getPos(entity)
return selectorDecision((s.masks[index] >> bitpos) & 0x3)
}
func (s *SelectorDecisionCache) getPos(entity uint64) (int, int) {
// 2 bits per entity, a uint64 mask can hold 32 entities
offset := (entity - s.base) % s.numEntries
return int(offset >> 5), int(offset&0x1F) * 2
}