Allow overshooting maximum when there are no bandwidth constraints. (#739)

* Allow overshooting maximum when there are no bandwidth constraints.

Some clients prioritize sending higher layer of video (for e.g.
Firefox). They may get into a state where congestion does not allow
sending lower layers.

That combined with adaptive streaming capping the max layer at a
certain level, it is possible to get into a state where video is
not streamed.

To make this experience better, allow overshoot beyond max layers
in case of optimal (i. e. no congestion) allocation.

NOTE: This means that the video could freeze when there is congestion
even if `AllowPause` is not disabled as in congested state, we do
not overshoot the max layer.

* log about allowing overshoot
This commit is contained in:
Raja Subramanian
2022-05-30 13:51:59 +05:30
committed by GitHub
parent 73808a1623
commit 10b0c9b9ff
2 changed files with 68 additions and 5 deletions
+34
View File
@@ -482,6 +482,40 @@ func (f *Forwarder) AllocateOptimal(brs Bitrates) VideoAllocation {
break
}
}
if bandwidthRequested == 0 {
// if we cannot allocate anything below max layer,
// look for a layer above. It is okay to overshoot
// in optimal allocation (i. e. no bandwidth restricstions).
// It is possible that clients send only a higher layer.
// To accommodate cases like that, try finding a layer
// above the requested maximum to ensure streaming
for s := DefaultMaxLayerSpatial; s >= 0; s-- {
for t := DefaultMaxLayerTemporal; t >= 0; t-- {
if brs[s][t] == 0 {
continue
}
targetLayers = VideoLayers{
Spatial: s,
Temporal: t,
}
bandwidthRequested = brs[s][t]
state = VideoAllocationStateOptimal
if f.targetLayers == InvalidLayers {
change = VideoStreamingChangeResuming
}
f.logger.Infow("allowing overshoot", "maxLayer", f.maxLayers, "targetLayers", targetLayers)
break
}
if bandwidthRequested != 0 {
break
}
}
}
}
if !targetLayers.IsValid() {
+34 -5
View File
@@ -233,6 +233,35 @@ func TestForwarderAllocate(t *testing.T) {
require.Equal(t, InvalidLayers, f.CurrentLayers())
// allocate using bitrates, allocation should choose optimal
f.UpTrackLayersChange([]int32{0, 1, 2})
f.maxLayers = VideoLayers{Spatial: 1, Temporal: 3}
expectedTargetLayers = VideoLayers{
Spatial: 1,
Temporal: 3,
}
expectedResult = VideoAllocation{
state: VideoAllocationStateOptimal,
change: VideoStreamingChangeNone,
bandwidthRequested: bitrates[1][3],
bandwidthDelta: bitrates[1][3],
availableLayers: []int32{0, 1, 2},
bitrates: bitrates,
targetLayers: expectedTargetLayers,
distanceToDesired: 0,
}
result = f.AllocateOptimal(bitrates)
require.Equal(t, expectedResult, result)
require.Equal(t, expectedResult, f.lastAllocation)
require.Equal(t, InvalidLayers, f.CurrentLayers())
require.Equal(t, expectedTargetLayers, f.TargetLayers())
// allocate using bitrates above maximum layer
f.UpTrackLayersChange([]int32{2})
sparseBitrates := Bitrates{
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 7, 0, 0},
}
expectedTargetLayers = VideoLayers{
Spatial: 2,
Temporal: 1,
@@ -240,14 +269,14 @@ func TestForwarderAllocate(t *testing.T) {
expectedResult = VideoAllocation{
state: VideoAllocationStateOptimal,
change: VideoStreamingChangeNone,
bandwidthRequested: bitrates[2][1],
bandwidthDelta: bitrates[2][1],
availableLayers: []int32{0},
bitrates: bitrates,
bandwidthRequested: sparseBitrates[2][1],
bandwidthDelta: sparseBitrates[2][1] - bitrates[1][3],
availableLayers: []int32{2},
bitrates: sparseBitrates,
targetLayers: expectedTargetLayers,
distanceToDesired: 0,
}
result = f.AllocateOptimal(bitrates)
result = f.AllocateOptimal(sparseBitrates)
require.Equal(t, expectedResult, result)
require.Equal(t, expectedResult, f.lastAllocation)
require.Equal(t, InvalidLayers, f.CurrentLayers())