mirror of
https://github.com/livekit/livekit.git
synced 2026-03-30 19:55:41 +00:00
Chaging VideoLayers -> VideoLayer (#1591)
There was mixed used. It is a struct. So, it is a singular. Change all the places I could find. There may be more, but can be changed when spotted.
This commit is contained in:
@@ -11,12 +11,12 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
InvalidLayers = VideoLayer{
|
||||
InvalidLayer = VideoLayer{
|
||||
Spatial: InvalidLayerSpatial,
|
||||
Temporal: InvalidLayerTemporal,
|
||||
}
|
||||
|
||||
DefaultMaxLayers = VideoLayer{
|
||||
DefaultMaxLayer = VideoLayer{
|
||||
Spatial: DefaultMaxLayerSpatial,
|
||||
Temporal: DefaultMaxLayerTemporal,
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ type DownTrackStreamAllocatorListener interface {
|
||||
OnSubscriptionChanged(dt *DownTrack)
|
||||
|
||||
// subscribed max video layer changed
|
||||
OnSubscribedLayersChanged(dt *DownTrack, layers buffer.VideoLayer)
|
||||
OnSubscribedLayerChanged(dt *DownTrack, layers buffer.VideoLayer)
|
||||
|
||||
// stream resumed
|
||||
OnResume(dt *DownTrack)
|
||||
@@ -259,7 +259,7 @@ func NewDownTrack(
|
||||
codec: codecs[0].RTPCodecCapability,
|
||||
}
|
||||
d.forwarder = NewForwarder(d.kind, d.logger, d.receiver.GetReferenceLayerRTPTimestamp)
|
||||
d.forwarder.OnParkedLayersExpired(func() {
|
||||
d.forwarder.OnParkedLayerExpired(func() {
|
||||
if sal := d.getStreamAllocatorListener(); sal != nil {
|
||||
sal.OnSubscriptionChanged(d)
|
||||
}
|
||||
@@ -599,10 +599,8 @@ func (d *DownTrack) WriteRTP(extPkt *buffer.ExtPacket, layer int32) error {
|
||||
|
||||
if extPkt.KeyFrame {
|
||||
d.isNACKThrottled.Store(false)
|
||||
if extPkt.KeyFrame {
|
||||
d.rtpStats.UpdateKeyFrame(1)
|
||||
d.logger.Debugw("forwarding key frame", "layer", layer)
|
||||
}
|
||||
d.rtpStats.UpdateKeyFrame(1)
|
||||
d.logger.Debugw("forwarding key frame", "layer", layer)
|
||||
|
||||
// SVC-TODO - no need for key frame always when using SVC
|
||||
locked, _ := d.forwarder.CheckSync()
|
||||
@@ -716,17 +714,17 @@ func (d *DownTrack) WritePaddingRTP(bytesToSend int, paddingOnMute bool) int {
|
||||
|
||||
// Mute enables or disables media forwarding - subscriber triggered
|
||||
func (d *DownTrack) Mute(muted bool) {
|
||||
changed, maxLayers := d.forwarder.Mute(muted)
|
||||
d.handleMute(muted, false, changed, maxLayers)
|
||||
changed, maxLayer := d.forwarder.Mute(muted)
|
||||
d.handleMute(muted, false, changed, maxLayer)
|
||||
}
|
||||
|
||||
// PubMute enables or disables media forwarding - publisher side
|
||||
func (d *DownTrack) PubMute(pubMuted bool) {
|
||||
changed, maxLayers := d.forwarder.PubMute(pubMuted)
|
||||
d.handleMute(pubMuted, true, changed, maxLayers)
|
||||
changed, maxLayer := d.forwarder.PubMute(pubMuted)
|
||||
d.handleMute(pubMuted, true, changed, maxLayer)
|
||||
}
|
||||
|
||||
func (d *DownTrack) handleMute(muted bool, isPub bool, changed bool, maxLayers buffer.VideoLayer) {
|
||||
func (d *DownTrack) handleMute(muted bool, isPub bool, changed bool, maxLayer buffer.VideoLayer) {
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
@@ -761,7 +759,7 @@ func (d *DownTrack) handleMute(muted bool, isPub bool, changed bool, maxLayers b
|
||||
// client might need to be notified to start layers
|
||||
// before locking can happen in the forwarder.
|
||||
//
|
||||
notifyLayer = maxLayers.Spatial
|
||||
notifyLayer = maxLayer.Spatial
|
||||
}
|
||||
d.onMaxSubscribedLayerChanged(d, notifyLayer)
|
||||
}
|
||||
@@ -860,12 +858,12 @@ func (d *DownTrack) CloseWithFlush(flush bool) {
|
||||
}
|
||||
|
||||
func (d *DownTrack) SetMaxSpatialLayer(spatialLayer int32) {
|
||||
changed, maxLayers, currentLayers := d.forwarder.SetMaxSpatialLayer(spatialLayer)
|
||||
changed, maxLayer, currentLayer := d.forwarder.SetMaxSpatialLayer(spatialLayer)
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
|
||||
if d.onMaxSubscribedLayerChanged != nil && d.kind == webrtc.RTPCodecTypeVideo && maxLayers.SpatialGreaterThanOrEqual(currentLayers) {
|
||||
if d.onMaxSubscribedLayerChanged != nil && d.kind == webrtc.RTPCodecTypeVideo && maxLayer.SpatialGreaterThanOrEqual(currentLayer) {
|
||||
//
|
||||
// Notify when new max is
|
||||
// 1. Equal to current -> already locked to the new max
|
||||
@@ -873,27 +871,27 @@ func (d *DownTrack) SetMaxSpatialLayer(spatialLayer int32) {
|
||||
// a. is higher than previous max -> client may need to start higher layer before forwarder can lock
|
||||
// b. is lower than previous max -> client can stop higher layer(s)
|
||||
//
|
||||
d.onMaxSubscribedLayerChanged(d, maxLayers.Spatial)
|
||||
d.onMaxSubscribedLayerChanged(d, maxLayer.Spatial)
|
||||
}
|
||||
|
||||
if sal := d.getStreamAllocatorListener(); sal != nil {
|
||||
sal.OnSubscribedLayersChanged(d, maxLayers)
|
||||
sal.OnSubscribedLayerChanged(d, maxLayer)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DownTrack) SetMaxTemporalLayer(temporalLayer int32) {
|
||||
changed, maxLayers, _ := d.forwarder.SetMaxTemporalLayer(temporalLayer)
|
||||
changed, maxLayer, _ := d.forwarder.SetMaxTemporalLayer(temporalLayer)
|
||||
if !changed {
|
||||
return
|
||||
}
|
||||
|
||||
if sal := d.getStreamAllocatorListener(); sal != nil {
|
||||
sal.OnSubscribedLayersChanged(d, maxLayers)
|
||||
sal.OnSubscribedLayerChanged(d, maxLayer)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DownTrack) MaxLayers() buffer.VideoLayer {
|
||||
return d.forwarder.MaxLayers()
|
||||
func (d *DownTrack) MaxLayer() buffer.VideoLayer {
|
||||
return d.forwarder.MaxLayer()
|
||||
}
|
||||
|
||||
func (d *DownTrack) GetState() DownTrackState {
|
||||
@@ -1566,7 +1564,7 @@ func (d *DownTrack) DebugInfo() map[string]interface{} {
|
||||
"Bound": d.bound.Load(),
|
||||
"Muted": d.forwarder.IsMuted(),
|
||||
"PubMuted": d.forwarder.IsPubMuted(),
|
||||
"CurrentSpatialLayer": d.forwarder.CurrentLayers().Spatial,
|
||||
"CurrentSpatialLayer": d.forwarder.CurrentLayer().Spatial,
|
||||
"Stats": stats,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ import (
|
||||
|
||||
// Forwarder
|
||||
const (
|
||||
FlagPauseOnDowngrade = true
|
||||
FlagFilterRTX = true
|
||||
TransitionCostSpatial = 10
|
||||
ParkedLayersWaitDuration = 2 * time.Second
|
||||
FlagPauseOnDowngrade = true
|
||||
FlagFilterRTX = true
|
||||
TransitionCostSpatial = 10
|
||||
ParkedLayerWaitDuration = 2 * time.Second
|
||||
)
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
@@ -64,9 +64,9 @@ type VideoAllocation struct {
|
||||
BandwidthDelta int64
|
||||
BandwidthNeeded int64
|
||||
Bitrates Bitrates
|
||||
TargetLayers buffer.VideoLayer
|
||||
TargetLayer buffer.VideoLayer
|
||||
RequestLayerSpatial int32
|
||||
MaxLayers buffer.VideoLayer
|
||||
MaxLayer buffer.VideoLayer
|
||||
DistanceToDesired float64
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ func (v VideoAllocation) String() string {
|
||||
v.BandwidthDelta,
|
||||
v.BandwidthNeeded,
|
||||
v.Bitrates,
|
||||
v.TargetLayers,
|
||||
v.TargetLayer,
|
||||
v.RequestLayerSpatial,
|
||||
v.MaxLayers,
|
||||
v.MaxLayer,
|
||||
v.DistanceToDesired,
|
||||
)
|
||||
}
|
||||
@@ -88,9 +88,9 @@ func (v VideoAllocation) String() string {
|
||||
var (
|
||||
VideoAllocationDefault = VideoAllocation{
|
||||
PauseReason: VideoPauseReasonFeedDry, // start with no feed till feed is seen
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.InvalidLayers,
|
||||
MaxLayer: buffer.InvalidLayer,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -102,10 +102,10 @@ type VideoAllocationProvisional struct {
|
||||
maxSeenLayer buffer.VideoLayer
|
||||
availableLayers []int32
|
||||
Bitrates Bitrates
|
||||
maxLayers buffer.VideoLayer
|
||||
currentLayers buffer.VideoLayer
|
||||
parkedLayers buffer.VideoLayer
|
||||
allocatedLayers buffer.VideoLayer
|
||||
maxLayer buffer.VideoLayer
|
||||
currentLayer buffer.VideoLayer
|
||||
parkedLayer buffer.VideoLayer
|
||||
allocatedLayer buffer.VideoLayer
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
@@ -165,7 +165,7 @@ type Forwarder struct {
|
||||
lastSSRC uint32
|
||||
referenceLayerSpatial int32
|
||||
|
||||
parkedLayersTimer *time.Timer
|
||||
parkedLayerTimer *time.Timer
|
||||
|
||||
provisional *VideoAllocationProvisional
|
||||
|
||||
@@ -177,7 +177,7 @@ type Forwarder struct {
|
||||
|
||||
codecMunger codecmunger.CodecMunger
|
||||
|
||||
onParkedLayersExpired func()
|
||||
onParkedLayerExpired func()
|
||||
}
|
||||
|
||||
func NewForwarder(
|
||||
@@ -228,18 +228,18 @@ func (f *Forwarder) SetMaxTemporalLayerSeen(maxTemporalLayerSeen int32) {
|
||||
f.logger.Debugw("setting max temporal layer seen", "maxTemporalLayerSeen", maxTemporalLayerSeen)
|
||||
}
|
||||
|
||||
func (f *Forwarder) OnParkedLayersExpired(fn func()) {
|
||||
func (f *Forwarder) OnParkedLayerExpired(fn func()) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
f.onParkedLayersExpired = fn
|
||||
f.onParkedLayerExpired = fn
|
||||
}
|
||||
|
||||
func (f *Forwarder) getOnParkedLayersExpired() func() {
|
||||
func (f *Forwarder) getOnParkedLayerExpired() func() {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.onParkedLayersExpired
|
||||
return f.onParkedLayerExpired
|
||||
}
|
||||
|
||||
func (f *Forwarder) DetermineCodec(codec webrtc.RTPCodecCapability, extensions []webrtc.RTPHeaderExtensionParameter) {
|
||||
@@ -374,12 +374,12 @@ func (f *Forwarder) PubMute(pubMuted bool) (bool, buffer.VideoLayer) {
|
||||
f.resyncLocked()
|
||||
}
|
||||
} else {
|
||||
// Do not resync on publisher mute as forwarding can continue on unmute using same layers.
|
||||
// Do not resync on publisher mute as forwarding can continue on unmute using same layer.
|
||||
// On unmute, park current layers as streaming can continue without a key frame when publisher starts the stream.
|
||||
targetLayer := f.vls.GetTarget()
|
||||
if !pubMuted && targetLayer.IsValid() && f.vls.GetCurrent().Spatial == targetLayer.Spatial {
|
||||
f.setupParkedLayers(targetLayer)
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.setupParkedLayer(targetLayer)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ func (f *Forwarder) SetMaxSpatialLayer(spatialLayer int32) (bool, buffer.VideoLa
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.kind == webrtc.RTPCodecTypeAudio {
|
||||
return false, buffer.InvalidLayers, buffer.InvalidLayers
|
||||
return false, buffer.InvalidLayer, buffer.InvalidLayer
|
||||
}
|
||||
|
||||
existingMax := f.vls.GetMax()
|
||||
@@ -416,7 +416,7 @@ func (f *Forwarder) SetMaxSpatialLayer(spatialLayer int32) (bool, buffer.VideoLa
|
||||
f.logger.Debugw("setting max spatial layer", "layer", spatialLayer)
|
||||
f.vls.SetMaxSpatial(spatialLayer)
|
||||
|
||||
f.clearParkedLayers()
|
||||
f.clearParkedLayer()
|
||||
|
||||
return true, f.vls.GetMax(), f.vls.GetCurrent()
|
||||
}
|
||||
@@ -426,7 +426,7 @@ func (f *Forwarder) SetMaxTemporalLayer(temporalLayer int32) (bool, buffer.Video
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.kind == webrtc.RTPCodecTypeAudio {
|
||||
return false, buffer.InvalidLayers, buffer.InvalidLayers
|
||||
return false, buffer.InvalidLayer, buffer.InvalidLayer
|
||||
}
|
||||
|
||||
existingMax := f.vls.GetMax()
|
||||
@@ -437,26 +437,26 @@ func (f *Forwarder) SetMaxTemporalLayer(temporalLayer int32) (bool, buffer.Video
|
||||
f.logger.Debugw("setting max temporal layer", "layer", temporalLayer)
|
||||
f.vls.SetMaxTemporal(temporalLayer)
|
||||
|
||||
f.clearParkedLayers()
|
||||
f.clearParkedLayer()
|
||||
|
||||
return true, f.vls.GetMax(), f.vls.GetCurrent()
|
||||
}
|
||||
|
||||
func (f *Forwarder) MaxLayers() buffer.VideoLayer {
|
||||
func (f *Forwarder) MaxLayer() buffer.VideoLayer {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.vls.GetMax()
|
||||
}
|
||||
|
||||
func (f *Forwarder) CurrentLayers() buffer.VideoLayer {
|
||||
func (f *Forwarder) CurrentLayer() buffer.VideoLayer {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.vls.GetCurrent()
|
||||
}
|
||||
|
||||
func (f *Forwarder) TargetLayers() buffer.VideoLayer {
|
||||
func (f *Forwarder) TargetLayer() buffer.VideoLayer {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -526,9 +526,9 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
alloc := VideoAllocation{
|
||||
PauseReason: VideoPauseReasonNone,
|
||||
Bitrates: brs,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: requestSpatial,
|
||||
MaxLayers: maxLayer,
|
||||
MaxLayer: maxLayer,
|
||||
}
|
||||
optimalBandwidthNeeded := getOptimalBandwidthNeeded(f.muted, f.pubMuted, maxSeenLayer.Spatial, brs, maxLayer)
|
||||
if optimalBandwidthNeeded == 0 {
|
||||
@@ -542,7 +542,7 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
if allowOvershoot && f.vls.IsOvershootOkay() && maxSeenLayer.Spatial > maxSpatial {
|
||||
maxSpatial = maxSeenLayer.Spatial
|
||||
}
|
||||
alloc.TargetLayers = buffer.VideoLayer{
|
||||
alloc.TargetLayer = buffer.VideoLayer{
|
||||
Spatial: int32(math.Min(float64(maxSeenLayer.Spatial), float64(maxSpatial))),
|
||||
Temporal: maxLayer.Temporal,
|
||||
}
|
||||
@@ -558,13 +558,13 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
case f.pubMuted:
|
||||
alloc.PauseReason = VideoPauseReasonPubMuted
|
||||
// leave it at current layers for opportunistic resume
|
||||
alloc.TargetLayers = currentLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayers.Spatial
|
||||
alloc.TargetLayer = currentLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayer.Spatial
|
||||
|
||||
case parkedLayer.IsValid():
|
||||
// if parked on a layer, let it continue
|
||||
alloc.TargetLayers = parkedLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayers.Spatial
|
||||
alloc.TargetLayer = parkedLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayer.Spatial
|
||||
|
||||
case len(availableLayers) == 0:
|
||||
// feed may be dry
|
||||
@@ -573,8 +573,8 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
// Covers the cases of
|
||||
// 1. mis-detection of layer stop - can continue streaming
|
||||
// 2. current layer resuming - can latch on when it starts
|
||||
alloc.TargetLayers = currentLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayers.Spatial
|
||||
alloc.TargetLayer = currentLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayer.Spatial
|
||||
} else {
|
||||
// opportunistically latch on to anything
|
||||
opportunisticAlloc()
|
||||
@@ -595,18 +595,18 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
if !isCurrentLayerAvailable && currentLayer.IsValid() {
|
||||
// current layer maybe stopped, move to highest available
|
||||
for _, l := range availableLayers {
|
||||
if l > alloc.TargetLayers.Spatial {
|
||||
alloc.TargetLayers.Spatial = l
|
||||
if l > alloc.TargetLayer.Spatial {
|
||||
alloc.TargetLayer.Spatial = l
|
||||
}
|
||||
}
|
||||
alloc.TargetLayers.Temporal = maxLayer.Temporal
|
||||
alloc.TargetLayer.Temporal = maxLayer.Temporal
|
||||
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayers.Spatial
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayer.Spatial
|
||||
} else {
|
||||
requestLayerSpatial := int32(math.Min(float64(maxLayer.Spatial), float64(maxSeenLayer.Spatial)))
|
||||
if currentLayer.IsValid() && requestLayerSpatial == requestSpatial && currentLayer.Spatial == requestSpatial {
|
||||
// current is locked to desired, stay there
|
||||
alloc.TargetLayers = buffer.VideoLayer{
|
||||
alloc.TargetLayer = buffer.VideoLayer{
|
||||
Spatial: requestSpatial,
|
||||
Temporal: maxLayer.Temporal,
|
||||
}
|
||||
@@ -619,11 +619,11 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
}
|
||||
}
|
||||
|
||||
if !alloc.TargetLayers.IsValid() {
|
||||
alloc.TargetLayers = buffer.InvalidLayers
|
||||
if !alloc.TargetLayer.IsValid() {
|
||||
alloc.TargetLayer = buffer.InvalidLayer
|
||||
alloc.RequestLayerSpatial = buffer.InvalidLayerSpatial
|
||||
}
|
||||
if alloc.TargetLayers.IsValid() {
|
||||
if alloc.TargetLayer.IsValid() {
|
||||
alloc.BandwidthRequested = optimalBandwidthNeeded
|
||||
}
|
||||
alloc.BandwidthDelta = alloc.BandwidthRequested - f.lastAllocation.BandwidthRequested
|
||||
@@ -633,7 +633,7 @@ func (f *Forwarder) AllocateOptimal(availableLayers []int32, brs Bitrates, allow
|
||||
f.vls.GetMaxSeen(),
|
||||
availableLayers,
|
||||
brs,
|
||||
alloc.TargetLayers,
|
||||
alloc.TargetLayer,
|
||||
f.vls.GetMax(),
|
||||
)
|
||||
|
||||
@@ -645,45 +645,45 @@ func (f *Forwarder) ProvisionalAllocatePrepare(availableLayers []int32, Bitrates
|
||||
defer f.lock.Unlock()
|
||||
|
||||
f.provisional = &VideoAllocationProvisional{
|
||||
allocatedLayers: buffer.InvalidLayers,
|
||||
muted: f.muted,
|
||||
pubMuted: f.pubMuted,
|
||||
maxSeenLayer: f.vls.GetMaxSeen(),
|
||||
Bitrates: Bitrates,
|
||||
maxLayers: f.vls.GetMax(),
|
||||
currentLayers: f.vls.GetCurrent(),
|
||||
parkedLayers: f.vls.GetParked(),
|
||||
allocatedLayer: buffer.InvalidLayer,
|
||||
muted: f.muted,
|
||||
pubMuted: f.pubMuted,
|
||||
maxSeenLayer: f.vls.GetMaxSeen(),
|
||||
Bitrates: Bitrates,
|
||||
maxLayer: f.vls.GetMax(),
|
||||
currentLayer: f.vls.GetCurrent(),
|
||||
parkedLayer: f.vls.GetParked(),
|
||||
}
|
||||
|
||||
f.provisional.availableLayers = make([]int32, len(availableLayers))
|
||||
copy(f.provisional.availableLayers, availableLayers)
|
||||
}
|
||||
|
||||
func (f *Forwarder) ProvisionalAllocate(availableChannelCapacity int64, layers buffer.VideoLayer, allowPause bool, allowOvershoot bool) int64 {
|
||||
func (f *Forwarder) ProvisionalAllocate(availableChannelCapacity int64, layer buffer.VideoLayer, allowPause bool, allowOvershoot bool) int64 {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.provisional.muted ||
|
||||
f.provisional.pubMuted ||
|
||||
f.provisional.maxSeenLayer.Spatial == buffer.InvalidLayerSpatial ||
|
||||
!f.provisional.maxLayers.IsValid() ||
|
||||
((!allowOvershoot || !f.vls.IsOvershootOkay()) && layers.GreaterThan(f.provisional.maxLayers)) {
|
||||
!f.provisional.maxLayer.IsValid() ||
|
||||
((!allowOvershoot || !f.vls.IsOvershootOkay()) && layer.GreaterThan(f.provisional.maxLayer)) {
|
||||
return 0
|
||||
}
|
||||
|
||||
requiredBitrate := f.provisional.Bitrates[layers.Spatial][layers.Temporal]
|
||||
requiredBitrate := f.provisional.Bitrates[layer.Spatial][layer.Temporal]
|
||||
if requiredBitrate == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
alreadyAllocatedBitrate := int64(0)
|
||||
if f.provisional.allocatedLayers.IsValid() {
|
||||
alreadyAllocatedBitrate = f.provisional.Bitrates[f.provisional.allocatedLayers.Spatial][f.provisional.allocatedLayers.Temporal]
|
||||
if f.provisional.allocatedLayer.IsValid() {
|
||||
alreadyAllocatedBitrate = f.provisional.Bitrates[f.provisional.allocatedLayer.Spatial][f.provisional.allocatedLayer.Temporal]
|
||||
}
|
||||
|
||||
// a layer under maximum fits, take it
|
||||
if !layers.GreaterThan(f.provisional.maxLayers) && requiredBitrate <= (availableChannelCapacity+alreadyAllocatedBitrate) {
|
||||
f.provisional.allocatedLayers = layers
|
||||
if !layer.GreaterThan(f.provisional.maxLayer) && requiredBitrate <= (availableChannelCapacity+alreadyAllocatedBitrate) {
|
||||
f.provisional.allocatedLayer = layer
|
||||
return requiredBitrate - alreadyAllocatedBitrate
|
||||
}
|
||||
|
||||
@@ -695,8 +695,8 @@ func (f *Forwarder) ProvisionalAllocate(availableChannelCapacity int64, layers b
|
||||
// 2. a layer above maximum which may or may not fit, but overshoot is allowed.
|
||||
// In any of those cases, take the lowest possible layer if pause is not allowed
|
||||
//
|
||||
if !allowPause && (!f.provisional.allocatedLayers.IsValid() || !layers.GreaterThan(f.provisional.allocatedLayers)) {
|
||||
f.provisional.allocatedLayers = layers
|
||||
if !allowPause && (!f.provisional.allocatedLayer.IsValid() || !layer.GreaterThan(f.provisional.allocatedLayer)) {
|
||||
f.provisional.allocatedLayer = layer
|
||||
return requiredBitrate - alreadyAllocatedBitrate
|
||||
}
|
||||
|
||||
@@ -727,14 +727,14 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.provisional.muted || f.provisional.pubMuted {
|
||||
f.provisional.allocatedLayers = buffer.InvalidLayers
|
||||
f.provisional.allocatedLayer = buffer.InvalidLayer
|
||||
if f.provisional.pubMuted {
|
||||
// leave it at current for opportunistic forwarding, there is still bandwidth saving with publisher mute
|
||||
f.provisional.allocatedLayers = f.provisional.currentLayers
|
||||
f.provisional.allocatedLayer = f.provisional.currentLayer
|
||||
}
|
||||
return VideoTransition{
|
||||
From: f.vls.GetTarget(),
|
||||
To: f.provisional.allocatedLayers,
|
||||
To: f.provisional.allocatedLayer,
|
||||
BandwidthDelta: 0 - f.lastAllocation.BandwidthRequested,
|
||||
}
|
||||
}
|
||||
@@ -743,12 +743,12 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
targetLayer := f.vls.GetTarget()
|
||||
if targetLayer.IsValid() {
|
||||
// what is the highest that is available
|
||||
maximalLayers := buffer.InvalidLayers
|
||||
maximalLayer := buffer.InvalidLayer
|
||||
maximalBandwidthRequired := int64(0)
|
||||
for s := f.provisional.maxLayers.Spatial; s >= 0; s-- {
|
||||
for t := f.provisional.maxLayers.Temporal; t >= 0; t-- {
|
||||
for s := f.provisional.maxLayer.Spatial; s >= 0; s-- {
|
||||
for t := f.provisional.maxLayer.Temporal; t >= 0; t-- {
|
||||
if f.provisional.Bitrates[s][t] != 0 {
|
||||
maximalLayers = buffer.VideoLayer{Spatial: s, Temporal: t}
|
||||
maximalLayer = buffer.VideoLayer{Spatial: s, Temporal: t}
|
||||
maximalBandwidthRequired = f.provisional.Bitrates[s][t]
|
||||
break
|
||||
}
|
||||
@@ -759,11 +759,11 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
}
|
||||
}
|
||||
|
||||
if maximalLayers.IsValid() {
|
||||
if !targetLayer.GreaterThan(maximalLayers) && f.provisional.Bitrates[targetLayer.Spatial][targetLayer.Temporal] != 0 {
|
||||
// currently streaming and maybe wanting an upgrade (targetLayer <= maximalLayers),
|
||||
if maximalLayer.IsValid() {
|
||||
if !targetLayer.GreaterThan(maximalLayer) && f.provisional.Bitrates[targetLayer.Spatial][targetLayer.Temporal] != 0 {
|
||||
// currently streaming and maybe wanting an upgrade (targetLayer <= maximalLayer),
|
||||
// just preserve current target in the cooperative scheme of things
|
||||
f.provisional.allocatedLayers = targetLayer
|
||||
f.provisional.allocatedLayer = targetLayer
|
||||
return VideoTransition{
|
||||
From: targetLayer,
|
||||
To: targetLayer,
|
||||
@@ -771,12 +771,12 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
}
|
||||
}
|
||||
|
||||
if targetLayer.GreaterThan(maximalLayers) {
|
||||
// maximalLayers < targetLayer, make the down move
|
||||
f.provisional.allocatedLayers = maximalLayers
|
||||
if targetLayer.GreaterThan(maximalLayer) {
|
||||
// maximalLayer < targetLayer, make the down move
|
||||
f.provisional.allocatedLayer = maximalLayer
|
||||
return VideoTransition{
|
||||
From: targetLayer,
|
||||
To: maximalLayers,
|
||||
To: maximalLayer,
|
||||
BandwidthDelta: maximalBandwidthRequired - f.lastAllocation.BandwidthRequested,
|
||||
}
|
||||
}
|
||||
@@ -787,7 +787,7 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
minSpatial, maxSpatial int32,
|
||||
minTemporal, maxTemporal int32,
|
||||
) (buffer.VideoLayer, int64) {
|
||||
layers := buffer.InvalidLayers
|
||||
layers := buffer.InvalidLayer
|
||||
bw := int64(0)
|
||||
for s := minSpatial; s <= maxSpatial; s++ {
|
||||
for t := minTemporal; t <= maxTemporal; t++ {
|
||||
@@ -812,14 +812,14 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
// NOTE: a layer in feed could have paused and there could be other options than going back to minimal,
|
||||
// but the cooperative scheme knocks things back to minimal
|
||||
targetLayer, bandwidthRequired = findNextLayer(
|
||||
0, f.provisional.maxLayers.Spatial,
|
||||
0, f.provisional.maxLayers.Temporal,
|
||||
0, f.provisional.maxLayer.Spatial,
|
||||
0, f.provisional.maxLayer.Temporal,
|
||||
)
|
||||
|
||||
// could not find a minimal layer, overshoot if allowed
|
||||
if bandwidthRequired == 0 && f.provisional.maxLayers.IsValid() && allowOvershoot && f.vls.IsOvershootOkay() {
|
||||
if bandwidthRequired == 0 && f.provisional.maxLayer.IsValid() && allowOvershoot && f.vls.IsOvershootOkay() {
|
||||
targetLayer, bandwidthRequired = findNextLayer(
|
||||
f.provisional.maxLayers.Spatial+1, buffer.DefaultMaxLayerSpatial,
|
||||
f.provisional.maxLayer.Spatial+1, buffer.DefaultMaxLayerSpatial,
|
||||
0, buffer.DefaultMaxLayerTemporal,
|
||||
)
|
||||
}
|
||||
@@ -827,14 +827,14 @@ func (f *Forwarder) ProvisionalAllocateGetCooperativeTransition(allowOvershoot b
|
||||
|
||||
// if nothing available, just leave target at current to enable opportunistic forwarding in case current resumes
|
||||
if !targetLayer.IsValid() {
|
||||
if f.provisional.parkedLayers.IsValid() {
|
||||
targetLayer = f.provisional.parkedLayers
|
||||
if f.provisional.parkedLayer.IsValid() {
|
||||
targetLayer = f.provisional.parkedLayer
|
||||
} else {
|
||||
targetLayer = f.provisional.currentLayers
|
||||
targetLayer = f.provisional.currentLayer
|
||||
}
|
||||
}
|
||||
|
||||
f.provisional.allocatedLayers = targetLayer
|
||||
f.provisional.allocatedLayer = targetLayer
|
||||
return VideoTransition{
|
||||
From: f.vls.GetTarget(),
|
||||
To: targetLayer,
|
||||
@@ -863,21 +863,21 @@ func (f *Forwarder) ProvisionalAllocateGetBestWeightedTransition() VideoTransiti
|
||||
|
||||
targetLayer := f.vls.GetTarget()
|
||||
if f.provisional.muted || f.provisional.pubMuted {
|
||||
f.provisional.allocatedLayers = buffer.InvalidLayers
|
||||
f.provisional.allocatedLayer = buffer.InvalidLayer
|
||||
if f.provisional.pubMuted {
|
||||
// leave it at current for opportunistic forwarding, there is still bandwidth saving with publisher mute
|
||||
f.provisional.allocatedLayers = f.provisional.currentLayers
|
||||
f.provisional.allocatedLayer = f.provisional.currentLayer
|
||||
}
|
||||
return VideoTransition{
|
||||
From: targetLayer,
|
||||
To: f.provisional.allocatedLayers,
|
||||
To: f.provisional.allocatedLayer,
|
||||
BandwidthDelta: 0 - f.lastAllocation.BandwidthRequested,
|
||||
}
|
||||
}
|
||||
|
||||
maxReachableLayerTemporal := buffer.InvalidLayerTemporal
|
||||
for t := f.provisional.maxLayers.Temporal; t >= 0; t-- {
|
||||
for s := f.provisional.maxLayers.Spatial; s >= 0; s-- {
|
||||
for t := f.provisional.maxLayer.Temporal; t >= 0; t-- {
|
||||
for s := f.provisional.maxLayer.Spatial; s >= 0; s-- {
|
||||
if f.provisional.Bitrates[s][t] != 0 {
|
||||
maxReachableLayerTemporal = t
|
||||
break
|
||||
@@ -892,21 +892,21 @@ func (f *Forwarder) ProvisionalAllocateGetBestWeightedTransition() VideoTransiti
|
||||
// feed has gone dry, just leave target at current to enable opportunistic forwarding in case current resumes.
|
||||
// Note that this is giving back bits and opportunistic forwarding resuming might trigger congestion again,
|
||||
// but that should be handled by stream allocator.
|
||||
if f.provisional.parkedLayers.IsValid() {
|
||||
f.provisional.allocatedLayers = f.provisional.parkedLayers
|
||||
if f.provisional.parkedLayer.IsValid() {
|
||||
f.provisional.allocatedLayer = f.provisional.parkedLayer
|
||||
} else {
|
||||
f.provisional.allocatedLayers = f.provisional.currentLayers
|
||||
f.provisional.allocatedLayer = f.provisional.currentLayer
|
||||
}
|
||||
return VideoTransition{
|
||||
From: targetLayer,
|
||||
To: f.provisional.allocatedLayers,
|
||||
To: f.provisional.allocatedLayer,
|
||||
BandwidthDelta: 0 - f.lastAllocation.BandwidthRequested,
|
||||
}
|
||||
}
|
||||
|
||||
// starting from minimum to target, find transition which gives the best
|
||||
// transition taking into account bits saved vs cost of such a transition
|
||||
bestLayers := buffer.InvalidLayers
|
||||
bestLayer := buffer.InvalidLayer
|
||||
bestBandwidthDelta := int64(0)
|
||||
bestValue := float32(0)
|
||||
for s := int32(0); s <= targetLayer.Spatial; s++ {
|
||||
@@ -932,15 +932,15 @@ func (f *Forwarder) ProvisionalAllocateGetBestWeightedTransition() VideoTransiti
|
||||
if value > bestValue || (value == bestValue && BandwidthDelta > bestBandwidthDelta) {
|
||||
bestValue = value
|
||||
bestBandwidthDelta = BandwidthDelta
|
||||
bestLayers = buffer.VideoLayer{Spatial: s, Temporal: t}
|
||||
bestLayer = buffer.VideoLayer{Spatial: s, Temporal: t}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.provisional.allocatedLayers = bestLayers
|
||||
f.provisional.allocatedLayer = bestLayer
|
||||
return VideoTransition{
|
||||
From: targetLayer,
|
||||
To: bestLayers,
|
||||
To: bestLayer,
|
||||
BandwidthDelta: bestBandwidthDelta,
|
||||
}
|
||||
}
|
||||
@@ -954,24 +954,24 @@ func (f *Forwarder) ProvisionalAllocateCommit() VideoAllocation {
|
||||
f.provisional.pubMuted,
|
||||
f.provisional.maxSeenLayer.Spatial,
|
||||
f.provisional.Bitrates,
|
||||
f.provisional.maxLayers,
|
||||
f.provisional.maxLayer,
|
||||
)
|
||||
alloc := VideoAllocation{
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: -f.lastAllocation.BandwidthRequested,
|
||||
Bitrates: f.provisional.Bitrates,
|
||||
BandwidthNeeded: optimalBandwidthNeeded,
|
||||
TargetLayers: f.provisional.allocatedLayers,
|
||||
RequestLayerSpatial: f.provisional.allocatedLayers.Spatial,
|
||||
MaxLayers: f.provisional.maxLayers,
|
||||
TargetLayer: f.provisional.allocatedLayer,
|
||||
RequestLayerSpatial: f.provisional.allocatedLayer.Spatial,
|
||||
MaxLayer: f.provisional.maxLayer,
|
||||
DistanceToDesired: getDistanceToDesired(
|
||||
f.provisional.muted,
|
||||
f.provisional.pubMuted,
|
||||
f.provisional.maxSeenLayer,
|
||||
f.provisional.availableLayers,
|
||||
f.provisional.Bitrates,
|
||||
f.provisional.allocatedLayers,
|
||||
f.provisional.maxLayers,
|
||||
f.provisional.allocatedLayer,
|
||||
f.provisional.maxLayer,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -983,46 +983,46 @@ func (f *Forwarder) ProvisionalAllocateCommit() VideoAllocation {
|
||||
alloc.PauseReason = VideoPauseReasonPubMuted
|
||||
|
||||
case optimalBandwidthNeeded == 0:
|
||||
if f.provisional.allocatedLayers.IsValid() {
|
||||
if f.provisional.allocatedLayer.IsValid() {
|
||||
// overshoot
|
||||
alloc.BandwidthRequested = f.provisional.Bitrates[f.provisional.allocatedLayers.Spatial][f.provisional.allocatedLayers.Temporal]
|
||||
alloc.BandwidthRequested = f.provisional.Bitrates[f.provisional.allocatedLayer.Spatial][f.provisional.allocatedLayer.Temporal]
|
||||
alloc.BandwidthDelta = alloc.BandwidthRequested - f.lastAllocation.BandwidthRequested
|
||||
} else {
|
||||
alloc.PauseReason = VideoPauseReasonFeedDry
|
||||
|
||||
// leave target at current for opportunistic forwarding
|
||||
if f.provisional.currentLayers.IsValid() && f.provisional.currentLayers.Spatial <= f.provisional.maxLayers.Spatial {
|
||||
f.provisional.allocatedLayers = f.provisional.currentLayers
|
||||
alloc.TargetLayers = f.provisional.allocatedLayers
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayers.Spatial
|
||||
if f.provisional.currentLayer.IsValid() && f.provisional.currentLayer.Spatial <= f.provisional.maxLayer.Spatial {
|
||||
f.provisional.allocatedLayer = f.provisional.currentLayer
|
||||
alloc.TargetLayer = f.provisional.allocatedLayer
|
||||
alloc.RequestLayerSpatial = alloc.TargetLayer.Spatial
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
if f.provisional.allocatedLayers.IsValid() {
|
||||
alloc.BandwidthRequested = f.provisional.Bitrates[f.provisional.allocatedLayers.Spatial][f.provisional.allocatedLayers.Temporal]
|
||||
if f.provisional.allocatedLayer.IsValid() {
|
||||
alloc.BandwidthRequested = f.provisional.Bitrates[f.provisional.allocatedLayer.Spatial][f.provisional.allocatedLayer.Temporal]
|
||||
}
|
||||
alloc.BandwidthDelta = alloc.BandwidthRequested - f.lastAllocation.BandwidthRequested
|
||||
|
||||
if f.provisional.allocatedLayers.GreaterThan(f.provisional.maxLayers) ||
|
||||
if f.provisional.allocatedLayer.GreaterThan(f.provisional.maxLayer) ||
|
||||
alloc.BandwidthRequested >= getOptimalBandwidthNeeded(
|
||||
f.provisional.muted,
|
||||
f.provisional.pubMuted,
|
||||
f.provisional.maxSeenLayer.Spatial,
|
||||
f.provisional.Bitrates,
|
||||
f.provisional.maxLayers,
|
||||
f.provisional.maxLayer,
|
||||
) {
|
||||
// could be greater than optimal if overshooting
|
||||
alloc.IsDeficient = false
|
||||
} else {
|
||||
alloc.IsDeficient = true
|
||||
if !f.provisional.allocatedLayers.IsValid() {
|
||||
if !f.provisional.allocatedLayer.IsValid() {
|
||||
alloc.PauseReason = VideoPauseReasonBandwidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.clearParkedLayers()
|
||||
f.clearParkedLayer()
|
||||
return f.updateAllocation(alloc, "cooperative")
|
||||
}
|
||||
|
||||
@@ -1077,9 +1077,9 @@ func (f *Forwarder) AllocateNextHigher(availableChannelCapacity int64, available
|
||||
BandwidthDelta: bandwidthRequested - alreadyAllocated,
|
||||
BandwidthNeeded: optimalBandwidthNeeded,
|
||||
Bitrates: brs,
|
||||
TargetLayers: newTargetLayer,
|
||||
TargetLayer: newTargetLayer,
|
||||
RequestLayerSpatial: newTargetLayer.Spatial,
|
||||
MaxLayers: maxLayer,
|
||||
MaxLayer: maxLayer,
|
||||
DistanceToDesired: getDistanceToDesired(
|
||||
f.muted,
|
||||
f.pubMuted,
|
||||
@@ -1236,16 +1236,16 @@ func (f *Forwarder) Pause(availableLayers []int32, brs Bitrates) VideoAllocation
|
||||
BandwidthDelta: 0 - f.lastAllocation.BandwidthRequested,
|
||||
Bitrates: brs,
|
||||
BandwidthNeeded: optimalBandwidthNeeded,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: maxLayer,
|
||||
MaxLayer: maxLayer,
|
||||
DistanceToDesired: getDistanceToDesired(
|
||||
f.muted,
|
||||
f.pubMuted,
|
||||
maxSeenLayer,
|
||||
availableLayers,
|
||||
brs,
|
||||
buffer.InvalidLayers,
|
||||
buffer.InvalidLayer,
|
||||
maxLayer,
|
||||
),
|
||||
}
|
||||
@@ -1266,19 +1266,19 @@ func (f *Forwarder) Pause(availableLayers []int32, brs Bitrates) VideoAllocation
|
||||
alloc.PauseReason = VideoPauseReasonBandwidth
|
||||
}
|
||||
|
||||
f.clearParkedLayers()
|
||||
f.clearParkedLayer()
|
||||
return f.updateAllocation(alloc, "pause")
|
||||
}
|
||||
|
||||
func (f *Forwarder) updateAllocation(alloc VideoAllocation, reason string) VideoAllocation {
|
||||
// restrict target temporal to 0 if codec does not support temporal layers
|
||||
if alloc.TargetLayers.IsValid() && strings.ToLower(f.codec.MimeType) == "video/h264" {
|
||||
alloc.TargetLayers.Temporal = 0
|
||||
if alloc.TargetLayer.IsValid() && strings.ToLower(f.codec.MimeType) == "video/h264" {
|
||||
alloc.TargetLayer.Temporal = 0
|
||||
}
|
||||
|
||||
if alloc.IsDeficient != f.lastAllocation.IsDeficient ||
|
||||
alloc.PauseReason != f.lastAllocation.PauseReason ||
|
||||
alloc.TargetLayers != f.lastAllocation.TargetLayers ||
|
||||
alloc.TargetLayer != f.lastAllocation.TargetLayer ||
|
||||
alloc.RequestLayerSpatial != f.lastAllocation.RequestLayerSpatial {
|
||||
if reason == "optimal" {
|
||||
f.logger.Debugw(fmt.Sprintf("stream allocation: %s", reason), "allocation", alloc)
|
||||
@@ -1288,7 +1288,7 @@ func (f *Forwarder) updateAllocation(alloc VideoAllocation, reason string) Video
|
||||
}
|
||||
f.lastAllocation = alloc
|
||||
|
||||
f.setTargetLayers(f.lastAllocation.TargetLayers, f.lastAllocation.RequestLayerSpatial)
|
||||
f.setTargetLayer(f.lastAllocation.TargetLayer, f.lastAllocation.RequestLayerSpatial)
|
||||
if !f.vls.GetTarget().IsValid() {
|
||||
f.resyncLocked()
|
||||
}
|
||||
@@ -1296,8 +1296,8 @@ func (f *Forwarder) updateAllocation(alloc VideoAllocation, reason string) Video
|
||||
return f.lastAllocation
|
||||
}
|
||||
|
||||
func (f *Forwarder) setTargetLayers(targetLayers buffer.VideoLayer, requestLayerSpatial int32) {
|
||||
f.vls.SetTarget(targetLayers)
|
||||
func (f *Forwarder) setTargetLayer(targetLayer buffer.VideoLayer, requestLayerSpatial int32) {
|
||||
f.vls.SetTarget(targetLayer)
|
||||
f.vls.SetRequestSpatial(requestLayerSpatial)
|
||||
}
|
||||
|
||||
@@ -1309,31 +1309,31 @@ func (f *Forwarder) Resync() {
|
||||
}
|
||||
|
||||
func (f *Forwarder) resyncLocked() {
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
f.lastSSRC = 0
|
||||
f.clearParkedLayers()
|
||||
f.clearParkedLayer()
|
||||
}
|
||||
|
||||
func (f *Forwarder) clearParkedLayers() {
|
||||
f.vls.SetParked(buffer.InvalidLayers)
|
||||
if f.parkedLayersTimer != nil {
|
||||
f.parkedLayersTimer.Stop()
|
||||
f.parkedLayersTimer = nil
|
||||
func (f *Forwarder) clearParkedLayer() {
|
||||
f.vls.SetParked(buffer.InvalidLayer)
|
||||
if f.parkedLayerTimer != nil {
|
||||
f.parkedLayerTimer.Stop()
|
||||
f.parkedLayerTimer = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Forwarder) setupParkedLayers(parkedLayers buffer.VideoLayer) {
|
||||
f.clearParkedLayers()
|
||||
func (f *Forwarder) setupParkedLayer(parkedLayer buffer.VideoLayer) {
|
||||
f.clearParkedLayer()
|
||||
|
||||
f.vls.SetParked(parkedLayers)
|
||||
f.parkedLayersTimer = time.AfterFunc(ParkedLayersWaitDuration, func() {
|
||||
f.vls.SetParked(parkedLayer)
|
||||
f.parkedLayerTimer = time.AfterFunc(ParkedLayerWaitDuration, func() {
|
||||
f.lock.Lock()
|
||||
notify := f.vls.GetParked().IsValid()
|
||||
f.clearParkedLayers()
|
||||
f.clearParkedLayer()
|
||||
f.lock.Unlock()
|
||||
|
||||
if onParkedLayersExpired := f.getOnParkedLayersExpired(); onParkedLayersExpired != nil && notify {
|
||||
onParkedLayersExpired()
|
||||
if onParkedLayerExpired := f.getOnParkedLayerExpired(); onParkedLayerExpired != nil && notify {
|
||||
onParkedLayerExpired()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1588,13 +1588,13 @@ func (f *Forwarder) GetRTPMungerParams() RTPMungerParams {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
func getOptimalBandwidthNeeded(muted bool, pubMuted bool, maxPublishedLayer int32, brs Bitrates, maxLayers buffer.VideoLayer) int64 {
|
||||
func getOptimalBandwidthNeeded(muted bool, pubMuted bool, maxPublishedLayer int32, brs Bitrates, maxLayer buffer.VideoLayer) int64 {
|
||||
if muted || pubMuted || maxPublishedLayer == buffer.InvalidLayerSpatial {
|
||||
return 0
|
||||
}
|
||||
|
||||
for i := maxLayers.Spatial; i >= 0; i-- {
|
||||
for j := maxLayers.Temporal; j >= 0; j-- {
|
||||
for i := maxLayer.Spatial; i >= 0; i-- {
|
||||
for j := maxLayer.Temporal; j >= 0; j-- {
|
||||
if brs[i][j] == 0 {
|
||||
continue
|
||||
}
|
||||
@@ -1617,14 +1617,14 @@ func getDistanceToDesired(
|
||||
maxSeenLayer buffer.VideoLayer,
|
||||
availableLayers []int32,
|
||||
brs Bitrates,
|
||||
targetLayers buffer.VideoLayer,
|
||||
maxLayers buffer.VideoLayer,
|
||||
targetLayer buffer.VideoLayer,
|
||||
maxLayer buffer.VideoLayer,
|
||||
) float64 {
|
||||
if muted || pubMuted || !maxSeenLayer.IsValid() || !maxLayers.IsValid() {
|
||||
if muted || pubMuted || !maxSeenLayer.IsValid() || !maxLayer.IsValid() {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
adjustedMaxLayers := maxLayers
|
||||
adjustedMaxLayer := maxLayer
|
||||
|
||||
maxAvailableSpatial := buffer.InvalidLayerSpatial
|
||||
maxAvailableTemporal := buffer.InvalidLayerTemporal
|
||||
@@ -1651,48 +1651,48 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
if maxAvailableSpatial < adjustedMaxLayers.Spatial {
|
||||
adjustedMaxLayers.Spatial = maxAvailableSpatial
|
||||
if maxAvailableSpatial < adjustedMaxLayer.Spatial {
|
||||
adjustedMaxLayer.Spatial = maxAvailableSpatial
|
||||
}
|
||||
|
||||
if maxSeenLayer.Spatial < adjustedMaxLayers.Spatial {
|
||||
adjustedMaxLayers.Spatial = maxSeenLayer.Spatial
|
||||
if maxSeenLayer.Spatial < adjustedMaxLayer.Spatial {
|
||||
adjustedMaxLayer.Spatial = maxSeenLayer.Spatial
|
||||
}
|
||||
|
||||
// max available temporal is min(subscribedMax, temporalLayerSeenMax, availableMax)
|
||||
// subscribedMax = subscriber requested max temporal layer
|
||||
// temporalLayerSeenMax = max temporal layer ever published/seen
|
||||
// availableMax = based on bit rate measurement, available max temporal in the adjusted max spatial layer
|
||||
if adjustedMaxLayers.Spatial != buffer.InvalidLayerSpatial {
|
||||
if adjustedMaxLayer.Spatial != buffer.InvalidLayerSpatial {
|
||||
for t := int32(len(brs[0])) - 1; t >= 0; t-- {
|
||||
if brs[adjustedMaxLayers.Spatial][t] != 0 {
|
||||
if brs[adjustedMaxLayer.Spatial][t] != 0 {
|
||||
maxAvailableTemporal = t
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if maxAvailableTemporal < adjustedMaxLayers.Temporal {
|
||||
adjustedMaxLayers.Temporal = maxAvailableTemporal
|
||||
if maxAvailableTemporal < adjustedMaxLayer.Temporal {
|
||||
adjustedMaxLayer.Temporal = maxAvailableTemporal
|
||||
}
|
||||
|
||||
if maxSeenLayer.Temporal < adjustedMaxLayers.Temporal {
|
||||
adjustedMaxLayers.Temporal = maxSeenLayer.Temporal
|
||||
if maxSeenLayer.Temporal < adjustedMaxLayer.Temporal {
|
||||
adjustedMaxLayer.Temporal = maxSeenLayer.Temporal
|
||||
}
|
||||
|
||||
if !adjustedMaxLayers.IsValid() {
|
||||
adjustedMaxLayers = buffer.VideoLayer{Spatial: 0, Temporal: 0}
|
||||
if !adjustedMaxLayer.IsValid() {
|
||||
adjustedMaxLayer = buffer.VideoLayer{Spatial: 0, Temporal: 0}
|
||||
}
|
||||
|
||||
// adjust target layers if they are invalid, i. e. not streaming
|
||||
adjustedTargetLayers := targetLayers
|
||||
if !targetLayers.IsValid() {
|
||||
adjustedTargetLayers = buffer.VideoLayer{Spatial: 0, Temporal: 0}
|
||||
adjustedTargetLayer := targetLayer
|
||||
if !targetLayer.IsValid() {
|
||||
adjustedTargetLayer = buffer.VideoLayer{Spatial: 0, Temporal: 0}
|
||||
}
|
||||
|
||||
distance :=
|
||||
((adjustedMaxLayers.Spatial - adjustedTargetLayers.Spatial) * (maxSeenLayer.Temporal + 1)) +
|
||||
(adjustedMaxLayers.Temporal - adjustedTargetLayers.Temporal)
|
||||
if !targetLayers.IsValid() {
|
||||
((adjustedMaxLayer.Spatial - adjustedTargetLayer.Spatial) * (maxSeenLayer.Temporal + 1)) +
|
||||
(adjustedMaxLayer.Temporal - adjustedTargetLayer.Temporal)
|
||||
if !targetLayer.IsValid() {
|
||||
distance++
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
)
|
||||
|
||||
func disable(f *Forwarder) {
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.vls.SetTarget(buffer.InvalidLayers)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
f.vls.SetTarget(buffer.InvalidLayer)
|
||||
}
|
||||
|
||||
func newForwarder(codec webrtc.RTPCodecCapability, kind webrtc.RTPCodecType) *Forwarder {
|
||||
@@ -40,74 +40,74 @@ func TestForwarderMute(t *testing.T) {
|
||||
func TestForwarderLayersAudio(t *testing.T) {
|
||||
f := newForwarder(testutils.TestOpusCodec, webrtc.RTPCodecTypeAudio)
|
||||
|
||||
require.Equal(t, buffer.InvalidLayers, f.MaxLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.MaxLayer())
|
||||
|
||||
require.Equal(t, buffer.InvalidLayers, f.CurrentLayers())
|
||||
require.Equal(t, buffer.InvalidLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.CurrentLayer())
|
||||
require.Equal(t, buffer.InvalidLayer, f.TargetLayer())
|
||||
|
||||
changed, maxLayers, currentLayers := f.SetMaxSpatialLayer(1)
|
||||
changed, maxLayer, currentLayer := f.SetMaxSpatialLayer(1)
|
||||
require.False(t, changed)
|
||||
require.Equal(t, buffer.InvalidLayers, maxLayers)
|
||||
require.Equal(t, buffer.InvalidLayers, currentLayers)
|
||||
require.Equal(t, buffer.InvalidLayer, maxLayer)
|
||||
require.Equal(t, buffer.InvalidLayer, currentLayer)
|
||||
|
||||
changed, maxLayers, currentLayers = f.SetMaxTemporalLayer(1)
|
||||
changed, maxLayer, currentLayer = f.SetMaxTemporalLayer(1)
|
||||
require.False(t, changed)
|
||||
require.Equal(t, buffer.InvalidLayers, maxLayers)
|
||||
require.Equal(t, buffer.InvalidLayers, currentLayers)
|
||||
require.Equal(t, buffer.InvalidLayer, maxLayer)
|
||||
require.Equal(t, buffer.InvalidLayer, currentLayer)
|
||||
|
||||
require.Equal(t, buffer.InvalidLayers, f.MaxLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.MaxLayer())
|
||||
}
|
||||
|
||||
func TestForwarderLayersVideo(t *testing.T) {
|
||||
f := newForwarder(testutils.TestVP8Codec, webrtc.RTPCodecTypeVideo)
|
||||
|
||||
maxLayers := f.MaxLayers()
|
||||
maxLayer := f.MaxLayer()
|
||||
expectedLayers := buffer.VideoLayer{Spatial: buffer.InvalidLayerSpatial, Temporal: buffer.DefaultMaxLayerTemporal}
|
||||
require.Equal(t, expectedLayers, maxLayers)
|
||||
require.Equal(t, expectedLayers, maxLayer)
|
||||
|
||||
require.Equal(t, buffer.InvalidLayers, f.CurrentLayers())
|
||||
require.Equal(t, buffer.InvalidLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.CurrentLayer())
|
||||
require.Equal(t, buffer.InvalidLayer, f.TargetLayer())
|
||||
|
||||
expectedLayers = buffer.VideoLayer{
|
||||
Spatial: buffer.DefaultMaxLayerSpatial,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal,
|
||||
}
|
||||
changed, maxLayers, currentLayers := f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial)
|
||||
changed, maxLayer, currentLayer := f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial)
|
||||
require.True(t, changed)
|
||||
require.Equal(t, expectedLayers, maxLayers)
|
||||
require.Equal(t, buffer.InvalidLayers, currentLayers)
|
||||
require.Equal(t, expectedLayers, maxLayer)
|
||||
require.Equal(t, buffer.InvalidLayer, currentLayer)
|
||||
|
||||
changed, maxLayers, currentLayers = f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial - 1)
|
||||
changed, maxLayer, currentLayer = f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial - 1)
|
||||
require.True(t, changed)
|
||||
expectedLayers = buffer.VideoLayer{
|
||||
Spatial: buffer.DefaultMaxLayerSpatial - 1,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal,
|
||||
}
|
||||
require.Equal(t, expectedLayers, maxLayers)
|
||||
require.Equal(t, expectedLayers, f.MaxLayers())
|
||||
require.Equal(t, buffer.InvalidLayers, currentLayers)
|
||||
require.Equal(t, expectedLayers, maxLayer)
|
||||
require.Equal(t, expectedLayers, f.MaxLayer())
|
||||
require.Equal(t, buffer.InvalidLayer, currentLayer)
|
||||
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 0, Temporal: 1})
|
||||
changed, maxLayers, currentLayers = f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial - 1)
|
||||
changed, maxLayer, currentLayer = f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial - 1)
|
||||
require.False(t, changed)
|
||||
require.Equal(t, expectedLayers, maxLayers)
|
||||
require.Equal(t, expectedLayers, f.MaxLayers())
|
||||
require.Equal(t, buffer.VideoLayer{Spatial: 0, Temporal: 1}, currentLayers)
|
||||
require.Equal(t, expectedLayers, maxLayer)
|
||||
require.Equal(t, expectedLayers, f.MaxLayer())
|
||||
require.Equal(t, buffer.VideoLayer{Spatial: 0, Temporal: 1}, currentLayer)
|
||||
|
||||
changed, maxLayers, currentLayers = f.SetMaxTemporalLayer(buffer.DefaultMaxLayerTemporal)
|
||||
changed, maxLayer, currentLayer = f.SetMaxTemporalLayer(buffer.DefaultMaxLayerTemporal)
|
||||
require.False(t, changed)
|
||||
require.Equal(t, expectedLayers, maxLayers)
|
||||
require.Equal(t, buffer.VideoLayer{Spatial: 0, Temporal: 1}, currentLayers)
|
||||
require.Equal(t, expectedLayers, maxLayer)
|
||||
require.Equal(t, buffer.VideoLayer{Spatial: 0, Temporal: 1}, currentLayer)
|
||||
|
||||
changed, maxLayers, currentLayers = f.SetMaxTemporalLayer(buffer.DefaultMaxLayerTemporal - 1)
|
||||
changed, maxLayer, currentLayer = f.SetMaxTemporalLayer(buffer.DefaultMaxLayerTemporal - 1)
|
||||
require.True(t, changed)
|
||||
expectedLayers = buffer.VideoLayer{
|
||||
Spatial: buffer.DefaultMaxLayerSpatial - 1,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal - 1,
|
||||
}
|
||||
require.Equal(t, expectedLayers, maxLayers)
|
||||
require.Equal(t, expectedLayers, f.MaxLayers())
|
||||
require.Equal(t, buffer.VideoLayer{Spatial: 0, Temporal: 1}, currentLayers)
|
||||
require.Equal(t, expectedLayers, maxLayer)
|
||||
require.Equal(t, expectedLayers, f.MaxLayer())
|
||||
require.Equal(t, buffer.VideoLayer{Spatial: 0, Temporal: 1}, currentLayer)
|
||||
}
|
||||
|
||||
func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
@@ -121,15 +121,15 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
}
|
||||
|
||||
// invalid max layers
|
||||
f.vls.SetMax(buffer.InvalidLayers)
|
||||
f.vls.SetMax(buffer.InvalidLayer)
|
||||
expectedResult := VideoAllocation{
|
||||
PauseReason: VideoPauseReasonFeedDry,
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.InvalidLayers,
|
||||
MaxLayer: buffer.InvalidLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result := f.AllocateOptimal(nil, bitrates, true)
|
||||
@@ -139,15 +139,15 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
f.SetMaxSpatialLayer(buffer.DefaultMaxLayerSpatial)
|
||||
f.SetMaxTemporalLayer(buffer.DefaultMaxLayerTemporal)
|
||||
|
||||
// should still have target at buffer.InvalidLayers until max publisher layer is available
|
||||
// should still have target at buffer.InvalidLayer until max publisher layer is available
|
||||
expectedResult = VideoAllocation{
|
||||
PauseReason: VideoPauseReasonFeedDry,
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, bitrates, true)
|
||||
@@ -164,9 +164,9 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, bitrates, true)
|
||||
@@ -183,9 +183,9 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, bitrates, true)
|
||||
@@ -204,16 +204,16 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: emptyBitrates,
|
||||
TargetLayers: f.vls.GetParked(),
|
||||
TargetLayer: f.vls.GetParked(),
|
||||
RequestLayerSpatial: f.vls.GetParked().Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, emptyBitrates, true)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, f.vls.GetParked(), f.TargetLayers())
|
||||
f.vls.SetParked(buffer.InvalidLayers)
|
||||
require.Equal(t, f.vls.GetParked(), f.TargetLayer())
|
||||
f.vls.SetParked(buffer.InvalidLayer)
|
||||
|
||||
// when max layers changes, target is opportunistic, but requested spatial layer should be at max
|
||||
f.SetMaxTemporalLayerSeen(3)
|
||||
@@ -224,23 +224,23 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthDelta: bitrates[1][3],
|
||||
BandwidthNeeded: bitrates[1][3],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: buffer.DefaultMaxLayer,
|
||||
RequestLayerSpatial: f.vls.GetMax().Spatial,
|
||||
MaxLayers: f.vls.GetMax(),
|
||||
MaxLayer: f.vls.GetMax(),
|
||||
DistanceToDesired: -1,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, bitrates, true)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, buffer.DefaultMaxLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.DefaultMaxLayer, f.TargetLayer())
|
||||
|
||||
// reset max layers for rest of the tests below
|
||||
f.vls.SetMax(buffer.DefaultMaxLayers)
|
||||
f.vls.SetMax(buffer.DefaultMaxLayer)
|
||||
|
||||
// when feed is dry and current is not valid, should set up for opportunistic forwarding
|
||||
// NOTE: feed is dry due to availableLayers = nil, some valid bitrates may be passed in here for testing purposes only
|
||||
disable(f)
|
||||
expectedTargetLayers := buffer.VideoLayer{
|
||||
expectedTargetLayer := buffer.VideoLayer{
|
||||
Spatial: 2,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal,
|
||||
}
|
||||
@@ -250,21 +250,21 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthDelta: bitrates[2][1] - bitrates[1][3],
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: -0.5,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, bitrates, true)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
|
||||
f.vls.SetTarget(buffer.VideoLayer{Spatial: 0, Temporal: 0}) // set to valid to trigger paths in tests below
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 0, Temporal: 3}) // set to valid to trigger paths in tests below
|
||||
|
||||
// when feed is dry and current is valid, should stay at current
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 3,
|
||||
}
|
||||
@@ -273,17 +273,17 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0 - bitrates[2][1],
|
||||
Bitrates: emptyBitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: -0.75,
|
||||
}
|
||||
result = f.AllocateOptimal(nil, emptyBitrates, true)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
|
||||
// opportunistic target if feed is not dry and current is not valid, i. e. not forwarding
|
||||
expectedResult = VideoAllocation{
|
||||
@@ -292,34 +292,34 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthDelta: bitrates[2][1],
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: buffer.DefaultMaxLayer,
|
||||
RequestLayerSpatial: 2,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: -0.5,
|
||||
}
|
||||
result = f.AllocateOptimal([]int32{0, 1}, bitrates, true)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, buffer.DefaultMaxLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.DefaultMaxLayer, f.TargetLayer())
|
||||
|
||||
// if feed is not dry and current is not locked, should be opportunistic (with and without overshoot)
|
||||
f.vls.SetTarget(buffer.InvalidLayers)
|
||||
f.vls.SetTarget(buffer.InvalidLayer)
|
||||
expectedResult = VideoAllocation{
|
||||
PauseReason: VideoPauseReasonFeedDry,
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0 - bitrates[2][1],
|
||||
Bitrates: emptyBitrates,
|
||||
TargetLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: buffer.DefaultMaxLayer,
|
||||
RequestLayerSpatial: 2,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: -1.0,
|
||||
}
|
||||
result = f.AllocateOptimal([]int32{0, 1}, emptyBitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
|
||||
f.vls.SetTarget(buffer.InvalidLayers)
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
f.vls.SetTarget(buffer.InvalidLayer)
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 2,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal,
|
||||
}
|
||||
@@ -329,9 +329,9 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthDelta: bitrates[2][1],
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: 2,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: -0.5,
|
||||
}
|
||||
result = f.AllocateOptimal([]int32{0, 1}, bitrates, true)
|
||||
@@ -340,7 +340,7 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
|
||||
// switches to highest available if feed is not dry and current is valid and current is not available
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 0, Temporal: 1})
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 1,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal,
|
||||
}
|
||||
@@ -350,9 +350,9 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthDelta: 0,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: 1,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0.5,
|
||||
}
|
||||
result = f.AllocateOptimal([]int32{1}, bitrates, true)
|
||||
@@ -363,7 +363,7 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
f.vls.SetMax(buffer.VideoLayer{Spatial: 0, Temporal: 1})
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 0, Temporal: 1})
|
||||
f.vls.SetRequestSpatial(0)
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 1,
|
||||
}
|
||||
@@ -372,9 +372,9 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0 - bitrates[2][1],
|
||||
Bitrates: emptyBitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: 0,
|
||||
MaxLayers: f.vls.GetMax(),
|
||||
MaxLayer: f.vls.GetMax(),
|
||||
DistanceToDesired: 0.0,
|
||||
}
|
||||
result = f.AllocateOptimal([]int32{0, 1}, emptyBitrates, true)
|
||||
@@ -385,7 +385,7 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
f.vls.SetMax(buffer.VideoLayer{Spatial: 2, Temporal: 1})
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 0, Temporal: 1})
|
||||
f.vls.SetRequestSpatial(0)
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 2,
|
||||
Temporal: 1,
|
||||
}
|
||||
@@ -394,9 +394,9 @@ func TestForwarderAllocateOptimal(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: emptyBitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: 2,
|
||||
MaxLayers: f.vls.GetMax(),
|
||||
MaxLayer: f.vls.GetMax(),
|
||||
DistanceToDesired: -1,
|
||||
}
|
||||
result = f.AllocateOptimal([]int32{0, 1}, emptyBitrates, true)
|
||||
@@ -436,7 +436,7 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
require.Equal(t, int64(0), usedBitrate)
|
||||
|
||||
// committing should set target to (1, 2)
|
||||
expectedTargetLayers := buffer.VideoLayer{
|
||||
expectedTargetLayer := buffer.VideoLayer{
|
||||
Spatial: 1,
|
||||
Temporal: 2,
|
||||
}
|
||||
@@ -446,24 +446,24 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
BandwidthDelta: bitrates[1][2],
|
||||
BandwidthNeeded: bitrates[2][3],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 1.25,
|
||||
}
|
||||
result := f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
|
||||
// when nothing fits and pausing disallowed, should allocate (0, 0)
|
||||
f.vls.SetTarget(buffer.InvalidLayers)
|
||||
f.vls.SetTarget(buffer.InvalidLayer)
|
||||
f.ProvisionalAllocatePrepare(nil, bitrates)
|
||||
usedBitrate = f.ProvisionalAllocate(0, buffer.VideoLayer{Spatial: 0, Temporal: 0}, false, false)
|
||||
require.Equal(t, int64(1), usedBitrate)
|
||||
|
||||
// committing should set target to (0, 0)
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 0,
|
||||
}
|
||||
@@ -473,15 +473,15 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
BandwidthDelta: bitrates[0][0] - bitrates[1][2],
|
||||
BandwidthNeeded: bitrates[2][3],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 2.75,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
|
||||
//
|
||||
// Test allowOvershoot.
|
||||
@@ -508,11 +508,11 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
require.Equal(t, bitrates[1][3]-bitrates[2][3], usedBitrate)
|
||||
|
||||
// committing should set target to (1, 3)
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 1,
|
||||
Temporal: 3,
|
||||
}
|
||||
expectedMaxLayers := buffer.VideoLayer{
|
||||
expectedMaxLayer := buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 3,
|
||||
}
|
||||
@@ -520,15 +520,15 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
BandwidthRequested: bitrates[1][3],
|
||||
BandwidthDelta: bitrates[1][3] - 1, // 1 is the last allocation bandwidth requested
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: -1.75,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
|
||||
//
|
||||
// Even if overshoot is allowed, but if higher layers do not have bit rates, should continue with current layer.
|
||||
@@ -555,7 +555,7 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
require.Equal(t, int64(0), usedBitrate)
|
||||
|
||||
// committing should set target to (0, 2), i. e. leave it at current for opportunistic forwarding
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 2,
|
||||
}
|
||||
@@ -564,15 +564,15 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
BandwidthRequested: bitrates[0][2],
|
||||
BandwidthDelta: bitrates[0][2] - 8, // 8 is the last allocation bandwidth requested
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: 0.25,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
|
||||
//
|
||||
// Same case as above, but current is above max, so target should go to invalid
|
||||
@@ -597,16 +597,16 @@ func TestForwarderProvisionalAllocate(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: 0.25,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, buffer.InvalidLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.InvalidLayers, f.CurrentLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.TargetLayer())
|
||||
require.Equal(t, buffer.InvalidLayer, f.CurrentLayer())
|
||||
}
|
||||
|
||||
func TestForwarderProvisionalAllocateMute(t *testing.T) {
|
||||
@@ -629,21 +629,21 @@ func TestForwarderProvisionalAllocateMute(t *testing.T) {
|
||||
usedBitrate = f.ProvisionalAllocate(bitrates[2][3], buffer.VideoLayer{Spatial: 1, Temporal: 2}, true, true)
|
||||
require.Equal(t, int64(0), usedBitrate)
|
||||
|
||||
// committing should set target to buffer.InvalidLayers as track is muted
|
||||
// committing should set target to buffer.InvalidLayer as track is muted
|
||||
expectedResult := VideoAllocation{
|
||||
PauseReason: VideoPauseReasonMuted,
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result := f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, buffer.InvalidLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.TargetLayer())
|
||||
}
|
||||
|
||||
func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
@@ -661,9 +661,9 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
|
||||
f.ProvisionalAllocatePrepare(nil, bitrates)
|
||||
|
||||
// from scratch (buffer.InvalidLayers) should give back layer (0, 0)
|
||||
// from scratch (buffer.InvalidLayer) should give back layer (0, 0)
|
||||
expectedTransition := VideoTransition{
|
||||
From: buffer.InvalidLayers,
|
||||
From: buffer.InvalidLayer,
|
||||
To: buffer.VideoLayer{Spatial: 0, Temporal: 0},
|
||||
BandwidthDelta: 1,
|
||||
}
|
||||
@@ -678,23 +678,23 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
BandwidthDelta: 1,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedLayers,
|
||||
TargetLayer: expectedLayers,
|
||||
RequestLayerSpatial: expectedLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 2.25,
|
||||
}
|
||||
result := f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedLayers, f.TargetLayer())
|
||||
|
||||
// a higher target that is already streaming, just maintain it
|
||||
targetLayers := buffer.VideoLayer{Spatial: 2, Temporal: 1}
|
||||
f.vls.SetTarget(targetLayers)
|
||||
targetLayer := buffer.VideoLayer{Spatial: 2, Temporal: 1}
|
||||
f.vls.SetTarget(targetLayer)
|
||||
f.lastAllocation.BandwidthRequested = 10
|
||||
expectedTransition = VideoTransition{
|
||||
From: targetLayers,
|
||||
To: targetLayers,
|
||||
From: targetLayer,
|
||||
To: targetLayer,
|
||||
BandwidthDelta: 0,
|
||||
}
|
||||
transition = f.ProvisionalAllocateGetCooperativeTransition(false)
|
||||
@@ -707,21 +707,21 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
TargetLayers: expectedLayers,
|
||||
TargetLayer: expectedLayers,
|
||||
RequestLayerSpatial: expectedLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0.0,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedLayers, f.TargetLayer())
|
||||
|
||||
// from a target that has become unavailable, should switch to lower available layer
|
||||
targetLayers = buffer.VideoLayer{Spatial: 2, Temporal: 2}
|
||||
f.vls.SetTarget(targetLayers)
|
||||
targetLayer = buffer.VideoLayer{Spatial: 2, Temporal: 2}
|
||||
f.vls.SetTarget(targetLayer)
|
||||
expectedTransition = VideoTransition{
|
||||
From: targetLayers,
|
||||
From: targetLayer,
|
||||
To: buffer.VideoLayer{Spatial: 2, Temporal: 1},
|
||||
BandwidthDelta: 0,
|
||||
}
|
||||
@@ -734,10 +734,10 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
f.Mute(true)
|
||||
f.ProvisionalAllocatePrepare(nil, bitrates)
|
||||
|
||||
// mute should send target to buffer.InvalidLayers
|
||||
// mute should send target to buffer.InvalidLayer
|
||||
expectedTransition = VideoTransition{
|
||||
From: buffer.VideoLayer{Spatial: 2, Temporal: 1},
|
||||
To: buffer.InvalidLayers,
|
||||
To: buffer.InvalidLayer,
|
||||
BandwidthDelta: -10,
|
||||
}
|
||||
transition = f.ProvisionalAllocateGetCooperativeTransition(false)
|
||||
@@ -757,12 +757,12 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
{9, 10, 0, 0},
|
||||
}
|
||||
|
||||
f.vls.SetTarget(buffer.InvalidLayers)
|
||||
f.vls.SetTarget(buffer.InvalidLayer)
|
||||
f.ProvisionalAllocatePrepare(nil, bitrates)
|
||||
|
||||
// from scratch (buffer.InvalidLayers) should go to a layer past maximum as overshoot is allowed
|
||||
// from scratch (buffer.InvalidLayer) should go to a layer past maximum as overshoot is allowed
|
||||
expectedTransition = VideoTransition{
|
||||
From: buffer.InvalidLayers,
|
||||
From: buffer.InvalidLayer,
|
||||
To: buffer.VideoLayer{Spatial: 1, Temporal: 0},
|
||||
BandwidthDelta: 5,
|
||||
}
|
||||
@@ -771,20 +771,20 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
|
||||
// committing should set target to (1, 0)
|
||||
expectedLayers = buffer.VideoLayer{Spatial: 1, Temporal: 0}
|
||||
expectedMaxLayers := buffer.VideoLayer{Spatial: 0, Temporal: buffer.DefaultMaxLayerTemporal}
|
||||
expectedMaxLayer := buffer.VideoLayer{Spatial: 0, Temporal: buffer.DefaultMaxLayerTemporal}
|
||||
expectedResult = VideoAllocation{
|
||||
BandwidthRequested: 5,
|
||||
BandwidthDelta: 5,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedLayers,
|
||||
TargetLayer: expectedLayers,
|
||||
RequestLayerSpatial: expectedLayers.Spatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: -1.0,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedLayers, f.TargetLayer())
|
||||
|
||||
//
|
||||
// Test continuing at current layers when feed is dry
|
||||
@@ -796,13 +796,13 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
}
|
||||
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 0, Temporal: 2})
|
||||
f.vls.SetTarget(buffer.InvalidLayers)
|
||||
f.vls.SetTarget(buffer.InvalidLayer)
|
||||
f.ProvisionalAllocatePrepare(nil, bitrates)
|
||||
|
||||
// from scratch (buffer.InvalidLayers) should go to current layer
|
||||
// NOTE: targetLayer is set to buffer.InvalidLayers for testing, but in practice current layers valid and target layers invalid should not happen
|
||||
// from scratch (buffer.InvalidLayer) should go to current layer
|
||||
// NOTE: targetLayer is set to buffer.InvalidLayer for testing, but in practice current layers valid and target layers invalid should not happen
|
||||
expectedTransition = VideoTransition{
|
||||
From: buffer.InvalidLayers,
|
||||
From: buffer.InvalidLayer,
|
||||
To: buffer.VideoLayer{Spatial: 0, Temporal: 2},
|
||||
BandwidthDelta: -5, // 5 was the bandwidth needed for the last allocation
|
||||
}
|
||||
@@ -815,30 +815,30 @@ func TestForwarderProvisionalAllocateGetCooperativeTransition(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: -5,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedLayers,
|
||||
TargetLayer: expectedLayers,
|
||||
RequestLayerSpatial: expectedLayers.Spatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: -0.5,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedLayers, f.TargetLayer())
|
||||
|
||||
// committing should set target to current layers to enable opportunistic forwarding
|
||||
expectedResult = VideoAllocation{
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0,
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedLayers,
|
||||
TargetLayer: expectedLayers,
|
||||
RequestLayerSpatial: expectedLayers.Spatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: -0.5,
|
||||
}
|
||||
result = f.ProvisionalAllocateCommit()
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedLayers, f.TargetLayer())
|
||||
}
|
||||
|
||||
func TestForwarderProvisionalAllocateGetBestWeightedTransition(t *testing.T) {
|
||||
@@ -857,7 +857,7 @@ func TestForwarderProvisionalAllocateGetBestWeightedTransition(t *testing.T) {
|
||||
f.vls.SetTarget(buffer.VideoLayer{Spatial: 2, Temporal: 2})
|
||||
f.lastAllocation.BandwidthRequested = bitrates[2][2]
|
||||
expectedTransition := VideoTransition{
|
||||
From: f.TargetLayers(),
|
||||
From: f.TargetLayer(),
|
||||
To: buffer.VideoLayer{Spatial: 2, Temporal: 0},
|
||||
BandwidthDelta: 2,
|
||||
}
|
||||
@@ -909,7 +909,7 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
})
|
||||
|
||||
// move from (0, 0) -> (0, 1), i.e. a higher temporal layer is available in the same spatial layer
|
||||
expectedTargetLayers := buffer.VideoLayer{
|
||||
expectedTargetLayer := buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 1,
|
||||
}
|
||||
@@ -919,15 +919,15 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthDelta: 1,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 2.0,
|
||||
}
|
||||
result, boosted = f.AllocateNextHigher(100_000_000, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.True(t, boosted)
|
||||
|
||||
// empty bitrates cannot increase layer, i. e. last allocation is left unchanged
|
||||
@@ -937,7 +937,7 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
|
||||
// move from (0, 1) -> (1, 0), i.e. a higher spatial layer is available
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: f.vls.GetCurrent().Spatial, Temporal: 1})
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 1,
|
||||
Temporal: 0,
|
||||
}
|
||||
@@ -947,20 +947,20 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthDelta: 1,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 1.25,
|
||||
}
|
||||
result, boosted = f.AllocateNextHigher(100_000_000, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.True(t, boosted)
|
||||
|
||||
// next higher, move from (1, 0) -> (1, 3), still deficient though
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: 1, Temporal: 0})
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 1,
|
||||
Temporal: 3,
|
||||
}
|
||||
@@ -970,20 +970,20 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthDelta: 1,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0.5,
|
||||
}
|
||||
result, boosted = f.AllocateNextHigher(100_000_000, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.True(t, boosted)
|
||||
|
||||
// next higher, move from (1, 3) -> (2, 1), optimal allocation
|
||||
f.vls.SetCurrent(buffer.VideoLayer{Spatial: f.vls.GetCurrent().Spatial, Temporal: 3})
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 2,
|
||||
Temporal: 1,
|
||||
}
|
||||
@@ -992,15 +992,15 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthDelta: 2,
|
||||
Bitrates: bitrates,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0.0,
|
||||
}
|
||||
result, boosted = f.AllocateNextHigher(100_000_000, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.True(t, boosted)
|
||||
|
||||
// ask again, should return not boosted as there is no room to go higher
|
||||
@@ -1008,7 +1008,7 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
result, boosted = f.AllocateNextHigher(100_000_000, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.False(t, boosted)
|
||||
|
||||
// turn off everything, allocating next layer should result in streaming lowest layers
|
||||
@@ -1016,7 +1016,7 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
f.lastAllocation.IsDeficient = true
|
||||
f.lastAllocation.BandwidthRequested = 0
|
||||
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: 0,
|
||||
}
|
||||
@@ -1026,15 +1026,15 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthDelta: 2,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 2.25,
|
||||
}
|
||||
result, boosted = f.AllocateNextHigher(100_000_000, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.True(t, boosted)
|
||||
|
||||
// no new available capacity cannot bump up layer
|
||||
@@ -1044,15 +1044,15 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthDelta: 2,
|
||||
BandwidthNeeded: bitrates[2][1],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 2.25,
|
||||
}
|
||||
result, boosted = f.AllocateNextHigher(0, nil, bitrates, false)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.False(t, boosted)
|
||||
|
||||
// test allowOvershoot
|
||||
@@ -1066,11 +1066,11 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
|
||||
f.vls.SetCurrent(f.vls.GetTarget())
|
||||
|
||||
expectedTargetLayers = buffer.VideoLayer{
|
||||
expectedTargetLayer = buffer.VideoLayer{
|
||||
Spatial: 1,
|
||||
Temporal: 0,
|
||||
}
|
||||
expectedMaxLayers := buffer.VideoLayer{
|
||||
expectedMaxLayer := buffer.VideoLayer{
|
||||
Spatial: 0,
|
||||
Temporal: buffer.DefaultMaxLayerTemporal,
|
||||
}
|
||||
@@ -1078,16 +1078,16 @@ func TestForwarderAllocateNextHigher(t *testing.T) {
|
||||
BandwidthRequested: bitrates[1][0],
|
||||
BandwidthDelta: bitrates[1][0],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: expectedTargetLayers,
|
||||
RequestLayerSpatial: expectedTargetLayers.Spatial,
|
||||
MaxLayers: expectedMaxLayers,
|
||||
TargetLayer: expectedTargetLayer,
|
||||
RequestLayerSpatial: expectedTargetLayer.Spatial,
|
||||
MaxLayer: expectedMaxLayer,
|
||||
DistanceToDesired: -1.0,
|
||||
}
|
||||
// overshoot should return (1, 0) even if there is not enough capacity
|
||||
result, boosted = f.AllocateNextHigher(bitrates[1][0]-1, nil, bitrates, true)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, expectedTargetLayers, f.TargetLayers())
|
||||
require.Equal(t, expectedTargetLayer, f.TargetLayer())
|
||||
require.True(t, boosted)
|
||||
}
|
||||
|
||||
@@ -1116,15 +1116,15 @@ func TestForwarderPause(t *testing.T) {
|
||||
BandwidthDelta: 0 - bitrates[0][0],
|
||||
BandwidthNeeded: bitrates[2][3],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 3,
|
||||
}
|
||||
result := f.Pause(nil, bitrates)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, buffer.InvalidLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.TargetLayer())
|
||||
}
|
||||
|
||||
func TestForwarderPauseMute(t *testing.T) {
|
||||
@@ -1150,15 +1150,15 @@ func TestForwarderPauseMute(t *testing.T) {
|
||||
BandwidthRequested: 0,
|
||||
BandwidthDelta: 0 - bitrates[0][0],
|
||||
Bitrates: bitrates,
|
||||
TargetLayers: buffer.InvalidLayers,
|
||||
TargetLayer: buffer.InvalidLayer,
|
||||
RequestLayerSpatial: buffer.InvalidLayerSpatial,
|
||||
MaxLayers: buffer.DefaultMaxLayers,
|
||||
MaxLayer: buffer.DefaultMaxLayer,
|
||||
DistanceToDesired: 0,
|
||||
}
|
||||
result := f.Pause(nil, bitrates)
|
||||
require.Equal(t, expectedResult, result)
|
||||
require.Equal(t, expectedResult, f.lastAllocation)
|
||||
require.Equal(t, buffer.InvalidLayers, f.TargetLayers())
|
||||
require.Equal(t, buffer.InvalidLayer, f.TargetLayer())
|
||||
}
|
||||
|
||||
func TestForwarderGetTranslationParamsMuted(t *testing.T) {
|
||||
@@ -1765,7 +1765,7 @@ func TestForwardGetSnTsForPadding(t *testing.T) {
|
||||
Spatial: 0,
|
||||
Temporal: 1,
|
||||
})
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
|
||||
// send it through so that forwarder locks onto stream
|
||||
_, _ = f.GetTranslationParams(extPkt, 0)
|
||||
@@ -1832,7 +1832,7 @@ func TestForwardGetSnTsForBlankFrames(t *testing.T) {
|
||||
Spatial: 0,
|
||||
Temporal: 1,
|
||||
})
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
|
||||
// send it through so that forwarder locks onto stream
|
||||
_, _ = f.GetTranslationParams(extPkt, 0)
|
||||
@@ -1902,7 +1902,7 @@ func TestForwardGetPaddingVP8(t *testing.T) {
|
||||
Spatial: 0,
|
||||
Temporal: 1,
|
||||
})
|
||||
f.vls.SetCurrent(buffer.InvalidLayers)
|
||||
f.vls.SetCurrent(buffer.InvalidLayer)
|
||||
|
||||
// send it through so that forwarder locks onto stream
|
||||
_, _ = f.GetTranslationParams(extPkt, 0)
|
||||
|
||||
@@ -396,12 +396,12 @@ func (s *StreamAllocator) OnSubscriptionChanged(downTrack *sfu.DownTrack) {
|
||||
s.maybePostEventAllocateTrack(downTrack)
|
||||
}
|
||||
|
||||
// called when subscribed layers changes (limiting max layers)
|
||||
func (s *StreamAllocator) OnSubscribedLayersChanged(downTrack *sfu.DownTrack, layers buffer.VideoLayer) {
|
||||
// called when subscribed layer changes (limiting max layer)
|
||||
func (s *StreamAllocator) OnSubscribedLayerChanged(downTrack *sfu.DownTrack, layer buffer.VideoLayer) {
|
||||
shouldPost := false
|
||||
s.videoTracksMu.Lock()
|
||||
if track := s.videoTracks[livekit.TrackID(downTrack.ID())]; track != nil {
|
||||
if track.SetMaxLayers(layers) && track.SetDirty(true) {
|
||||
if track.SetMaxLayer(layer) && track.SetDirty(true) {
|
||||
shouldPost = true
|
||||
}
|
||||
}
|
||||
@@ -941,12 +941,12 @@ func (s *StreamAllocator) allocateAllTracks() {
|
||||
// 1. Stream as many tracks as possible, i.e. no pauses.
|
||||
// 2. Try to give fair allocation to all track.
|
||||
//
|
||||
// Start with the lowest layers and give each track a chance at that layer and keep going up.
|
||||
// As long as there is enough bandwidth for tracks to stream at the lowest layers, the first goal is achieved.
|
||||
// Start with the lowest layer and give each track a chance at that layer and keep going up.
|
||||
// As long as there is enough bandwidth for tracks to stream at the lowest layer, the first goal is achieved.
|
||||
//
|
||||
// Tracks that have higher subscribed layers can use any additional available bandwidth. This tried to achieve the second goal.
|
||||
// Tracks that have higher subscribed layer can use any additional available bandwidth. This tried to achieve the second goal.
|
||||
//
|
||||
// If there is not enough bandwidth even for the lowest layers, tracks at lower priorities will be paused.
|
||||
// If there is not enough bandwidth even for the lowest layer, tracks at lower priorities will be paused.
|
||||
//
|
||||
update := NewStreamStateUpdate()
|
||||
|
||||
@@ -1002,13 +1002,13 @@ func (s *StreamAllocator) allocateAllTracks() {
|
||||
|
||||
for spatial := int32(0); spatial <= buffer.DefaultMaxLayerSpatial; spatial++ {
|
||||
for temporal := int32(0); temporal <= buffer.DefaultMaxLayerTemporal; temporal++ {
|
||||
layers := buffer.VideoLayer{
|
||||
layer := buffer.VideoLayer{
|
||||
Spatial: spatial,
|
||||
Temporal: temporal,
|
||||
}
|
||||
|
||||
for _, track := range sorted {
|
||||
usedChannelCapacity := track.ProvisionalAllocate(availableChannelCapacity, layers, s.params.Config.AllowPause, FlagAllowOvershootWhileDeficient)
|
||||
usedChannelCapacity := track.ProvisionalAllocate(availableChannelCapacity, layer, s.params.Config.AllowPause, FlagAllowOvershootWhileDeficient)
|
||||
availableChannelCapacity -= usedChannelCapacity
|
||||
if availableChannelCapacity < 0 {
|
||||
availableChannelCapacity = 0
|
||||
@@ -1164,7 +1164,7 @@ func (s *StreamAllocator) maybeProbe() {
|
||||
}
|
||||
|
||||
func (s *StreamAllocator) maybeProbeWithMedia() {
|
||||
// boost deficient track farthest from desired layers
|
||||
// boost deficient track farthest from desired layer
|
||||
for _, track := range s.getMaxDistanceSortedDeficient() {
|
||||
allocation, boosted := track.AllocateNextHigher(ChannelCapacityInfinity, FlagAllowOvershootInCatchup)
|
||||
if !boosted {
|
||||
@@ -1183,7 +1183,7 @@ func (s *StreamAllocator) maybeProbeWithMedia() {
|
||||
}
|
||||
|
||||
func (s *StreamAllocator) maybeProbeWithPadding() {
|
||||
// use deficient track farthest from desired layers to find how much to probe
|
||||
// use deficient track farthest from desired layer to find how much to probe
|
||||
for _, track := range s.getMaxDistanceSortedDeficient() {
|
||||
transition, available := track.GetNextHigherTransition(FlagAllowOvershootInProbe)
|
||||
if !available || transition.BandwidthDelta < 0 {
|
||||
|
||||
@@ -16,7 +16,7 @@ type Track struct {
|
||||
publisherID livekit.ParticipantID
|
||||
logger logger.Logger
|
||||
|
||||
maxLayers buffer.VideoLayer
|
||||
maxLayer buffer.VideoLayer
|
||||
|
||||
totalPackets uint32
|
||||
totalRepeatedNacks uint32
|
||||
@@ -42,7 +42,7 @@ func NewTrack(
|
||||
isPaused: true,
|
||||
}
|
||||
t.SetPriority(0)
|
||||
t.SetMaxLayers(downTrack.MaxLayers())
|
||||
t.SetMaxLayer(downTrack.MaxLayer())
|
||||
|
||||
return t
|
||||
}
|
||||
@@ -103,12 +103,12 @@ func (t *Track) PublisherID() livekit.ParticipantID {
|
||||
return t.publisherID
|
||||
}
|
||||
|
||||
func (t *Track) SetMaxLayers(layers buffer.VideoLayer) bool {
|
||||
if t.maxLayers == layers {
|
||||
func (t *Track) SetMaxLayer(layer buffer.VideoLayer) bool {
|
||||
if t.maxLayer == layer {
|
||||
return false
|
||||
}
|
||||
|
||||
t.maxLayers = layers
|
||||
t.maxLayer = layer
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -124,8 +124,8 @@ func (t *Track) ProvisionalAllocatePrepare() {
|
||||
t.downTrack.ProvisionalAllocatePrepare()
|
||||
}
|
||||
|
||||
func (t *Track) ProvisionalAllocate(availableChannelCapacity int64, layers buffer.VideoLayer, allowPause bool, allowOvershoot bool) int64 {
|
||||
return t.downTrack.ProvisionalAllocate(availableChannelCapacity, layers, allowPause, allowOvershoot)
|
||||
func (t *Track) ProvisionalAllocate(availableChannelCapacity int64, layer buffer.VideoLayer, allowPause bool, allowOvershoot bool) int64 {
|
||||
return t.downTrack.ProvisionalAllocate(availableChannelCapacity, layer, allowPause, allowOvershoot)
|
||||
}
|
||||
|
||||
func (t *Track) ProvisionalAllocateGetCooperativeTransition(allowOvershoot bool) sfu.VideoTransition {
|
||||
@@ -197,11 +197,11 @@ func (t TrackSorter) Less(i, j int) bool {
|
||||
return t[i].priority > t[j].priority
|
||||
}
|
||||
|
||||
if t[i].maxLayers.Spatial != t[j].maxLayers.Spatial {
|
||||
return t[i].maxLayers.Spatial > t[j].maxLayers.Spatial
|
||||
if t[i].maxLayer.Spatial != t[j].maxLayer.Spatial {
|
||||
return t[i].maxLayer.Spatial > t[j].maxLayer.Spatial
|
||||
}
|
||||
|
||||
return t[i].maxLayers.Temporal > t[j].maxLayers.Temporal
|
||||
return t[i].maxLayer.Temporal > t[j].maxLayer.Temporal
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
@@ -295,12 +295,12 @@ func (s *StreamTrackerManager) DistanceToDesired() float64 {
|
||||
|
||||
al, brs := s.getLayeredBitrateLocked()
|
||||
|
||||
maxLayers := buffer.InvalidLayers
|
||||
maxLayer := buffer.InvalidLayer
|
||||
done:
|
||||
for s := int32(len(brs)) - 1; s >= 0; s-- {
|
||||
for t := int32(len(brs[0])) - 1; t >= 0; t-- {
|
||||
if brs[s][t] != 0 {
|
||||
maxLayers = buffer.VideoLayer{
|
||||
maxLayer = buffer.VideoLayer{
|
||||
Spatial: s,
|
||||
Temporal: t,
|
||||
}
|
||||
@@ -311,21 +311,21 @@ done:
|
||||
|
||||
// before bit rate measurement is available, stream tracker could declare layer seen, account for that
|
||||
for _, layer := range al {
|
||||
if layer > maxLayers.Spatial {
|
||||
maxLayers.Spatial = layer
|
||||
maxLayers.Temporal = s.maxTemporalLayerSeen // till bit rate measurement is available, assume max seen as temporal
|
||||
if layer > maxLayer.Spatial {
|
||||
maxLayer.Spatial = layer
|
||||
maxLayer.Temporal = s.maxTemporalLayerSeen // till bit rate measurement is available, assume max seen as temporal
|
||||
}
|
||||
}
|
||||
|
||||
adjustedMaxLayers := maxLayers
|
||||
if !maxLayers.IsValid() {
|
||||
adjustedMaxLayers := maxLayer
|
||||
if !maxLayer.IsValid() {
|
||||
adjustedMaxLayers = buffer.VideoLayer{Spatial: 0, Temporal: 0}
|
||||
}
|
||||
|
||||
distance :=
|
||||
((s.maxExpectedLayer - adjustedMaxLayers.Spatial) * (s.maxTemporalLayerSeen + 1)) +
|
||||
(s.maxTemporalLayerSeen - adjustedMaxLayers.Temporal)
|
||||
if !maxLayers.IsValid() {
|
||||
if !maxLayer.IsValid() {
|
||||
distance++
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ type Base struct {
|
||||
func NewBase(logger logger.Logger) *Base {
|
||||
return &Base{
|
||||
logger: logger,
|
||||
maxLayer: buffer.InvalidLayers,
|
||||
targetLayer: buffer.InvalidLayers, // start off with nothing, let streamallocator/opportunistic forwarder set the target
|
||||
maxLayer: buffer.InvalidLayer,
|
||||
targetLayer: buffer.InvalidLayer, // start off with nothing, let streamallocator/opportunistic forwarder set the target
|
||||
requestSpatial: buffer.InvalidLayerSpatial,
|
||||
maxSeenLayer: buffer.InvalidLayers,
|
||||
parkedLayer: buffer.InvalidLayers,
|
||||
currentLayer: buffer.InvalidLayers,
|
||||
maxSeenLayer: buffer.InvalidLayer,
|
||||
parkedLayer: buffer.InvalidLayer,
|
||||
currentLayer: buffer.InvalidLayer,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func (s *Simulcast) Select(extPkt *buffer.ExtPacket, layer int32) (result VideoL
|
||||
if !isActive {
|
||||
result.IsResuming = true
|
||||
}
|
||||
s.SetParked(buffer.InvalidLayers)
|
||||
s.SetParked(buffer.InvalidLayer)
|
||||
if s.currentLayer.Spatial >= s.maxLayer.Spatial {
|
||||
result.IsSwitchingToMaxSpatial = true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user