mirror of
https://github.com/livekit/livekit.git
synced 2026-06-01 11:24:08 +00:00
Do not increase max expected layer on track info update. (#4285)
* Do not increase max expected layer on track info update. When max expected layer increases, the corresponding trackers are reset so that first packets from those layers can trigger a layer detected change enabling quick detection of layer start. A track info update changing max to what is in track info could set the max expected to be higher without resetting the tracker. And that would cause dynacast induced max layer change to miss tracker reset too. Sequence - dynacast sets max expected to 0 - track info update sets it to 2 - dynacast sets it to 1 --> this should have reset tracker on layer 1, but because it is less than current max (2), it is skipped. * thank you CodeRabbit * force update on start
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package dynacast
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"time"
|
||||
|
||||
"github.com/bep/debounce"
|
||||
@@ -216,9 +217,7 @@ func (d *dynacastManagerVideo) update(force bool) {
|
||||
|
||||
// commit change
|
||||
d.committedMaxSubscribedQuality = make(map[mime.MimeType]livekit.VideoQuality, len(d.maxSubscribedQuality))
|
||||
for mime, quality := range d.maxSubscribedQuality {
|
||||
d.committedMaxSubscribedQuality[mime] = quality
|
||||
}
|
||||
maps.Copy(d.committedMaxSubscribedQuality, d.maxSubscribedQuality)
|
||||
|
||||
d.enqueueSubscribedQualityChange()
|
||||
d.lock.Unlock()
|
||||
|
||||
@@ -16,7 +16,6 @@ package sfu
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -162,7 +161,8 @@ func NewStreamTrackerManager(
|
||||
s.trackerConfig = config.Video
|
||||
}
|
||||
|
||||
s.maxExpectedLayerFromTrackInfo()
|
||||
s.maxExpectedLayer = buffer.InvalidLayerSpatial
|
||||
s.maxExpectedLayerFromTrackInfo(true)
|
||||
|
||||
if trackInfo.Type == livekit.TrackType_VIDEO {
|
||||
go s.bitrateReporter()
|
||||
@@ -333,8 +333,12 @@ func (s *StreamTrackerManager) RemoveAllTrackers() {
|
||||
s.trackers[layer] = nil
|
||||
}
|
||||
s.availableLayers = make([]int32, 0)
|
||||
s.maxExpectedLayerFromTrackInfoLocked()
|
||||
|
||||
s.maxExpectedLayer = buffer.InvalidLayerSpatial
|
||||
s.maxExpectedLayerFromTrackInfoLocked(true)
|
||||
|
||||
s.paused = false
|
||||
|
||||
ddTracker := s.ddTracker
|
||||
s.ddTracker = nil
|
||||
s.lock.Unlock()
|
||||
@@ -382,7 +386,7 @@ func (s *StreamTrackerManager) IsPaused() bool {
|
||||
|
||||
func (s *StreamTrackerManager) UpdateTrackInfo(ti *livekit.TrackInfo) {
|
||||
s.trackInfo.Store(utils.CloneProto(ti))
|
||||
s.maxExpectedLayerFromTrackInfo()
|
||||
s.maxExpectedLayerFromTrackInfo(false)
|
||||
}
|
||||
|
||||
func (s *StreamTrackerManager) SetMaxExpectedSpatialLayer(layer int32) int32 {
|
||||
@@ -488,7 +492,7 @@ func (s *StreamTrackerManager) getLayeredBitrateLocked() ([]int32, Bitrates) {
|
||||
tls = tracker.BitrateTemporalCumulative()
|
||||
}
|
||||
|
||||
for j := 0; j < len(br[i]); j++ {
|
||||
for j := range len(br[i]) {
|
||||
br[i][j] = tls[j]
|
||||
}
|
||||
}
|
||||
@@ -515,20 +519,13 @@ func (s *StreamTrackerManager) getLayeredBitrateLocked() ([]int32, Bitrates) {
|
||||
|
||||
func (s *StreamTrackerManager) addAvailableLayer(layer int32) {
|
||||
s.lock.Lock()
|
||||
hasLayer := false
|
||||
for _, l := range s.availableLayers {
|
||||
if l == layer {
|
||||
hasLayer = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if hasLayer {
|
||||
if slices.Contains(s.availableLayers, layer) {
|
||||
s.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
s.availableLayers = append(s.availableLayers, layer)
|
||||
sort.Slice(s.availableLayers, func(i, j int) bool { return s.availableLayers[i] < s.availableLayers[j] })
|
||||
slices.Sort(s.availableLayers)
|
||||
|
||||
// check if new layer is the max layer
|
||||
isMaxLayerChange := s.availableLayers[len(s.availableLayers)-1] == layer
|
||||
@@ -562,7 +559,7 @@ func (s *StreamTrackerManager) removeAvailableLayer(layer int32) {
|
||||
newLayers = append(newLayers, l)
|
||||
}
|
||||
}
|
||||
sort.Slice(newLayers, func(i, j int) bool { return newLayers[i] < newLayers[j] })
|
||||
slices.Sort(newLayers)
|
||||
s.availableLayers = newLayers
|
||||
|
||||
s.logger.Debugw(
|
||||
@@ -588,23 +585,30 @@ func (s *StreamTrackerManager) removeAvailableLayer(layer int32) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StreamTrackerManager) maxExpectedLayerFromTrackInfo() {
|
||||
func (s *StreamTrackerManager) maxExpectedLayerFromTrackInfo(force bool) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.maxExpectedLayerFromTrackInfoLocked()
|
||||
s.maxExpectedLayerFromTrackInfoLocked(force)
|
||||
}
|
||||
|
||||
func (s *StreamTrackerManager) maxExpectedLayerFromTrackInfoLocked() {
|
||||
s.maxExpectedLayer = buffer.InvalidLayerSpatial
|
||||
func (s *StreamTrackerManager) maxExpectedLayerFromTrackInfoLocked(force bool) {
|
||||
maxExpectedLayer := buffer.InvalidLayerSpatial
|
||||
ti := s.trackInfo.Load()
|
||||
if ti != nil {
|
||||
for _, layer := range buffer.GetVideoLayersForMimeType(s.mimeType, ti) {
|
||||
if layer.SpatialLayer > s.maxExpectedLayer {
|
||||
s.maxExpectedLayer = layer.SpatialLayer
|
||||
if layer.SpatialLayer > maxExpectedLayer {
|
||||
maxExpectedLayer = layer.SpatialLayer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when max expected is higher than current max, trackers are reset
|
||||
// which allows a layer start to be detected on initial packets from that higher layer,
|
||||
// so update max only on track info max being lower than current max
|
||||
if force || maxExpectedLayer < s.maxExpectedLayer {
|
||||
s.maxExpectedLayer = maxExpectedLayer
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StreamTrackerManager) GetMaxTemporalLayerSeen() int32 {
|
||||
|
||||
Reference in New Issue
Block a user