-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify moving average loss controller
- Loading branch information
1 parent
62459b1
commit 221d52b
Showing
4 changed files
with
40 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,107 +1,50 @@ | ||
package gcc | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"time" | ||
|
||
"github.com/pion/interceptor/internal/types" | ||
) | ||
|
||
type lossBasedBWEConfig struct { | ||
lossWindow time.Duration | ||
maxLossWindow time.Duration | ||
maxAcknowledgedRateWindow time.Duration | ||
} | ||
|
||
type lossBasedBandwidthEstimator struct { | ||
config lossBasedBWEConfig | ||
|
||
bitrate types.DataRate | ||
averageLoss float64 | ||
maxAverageLoss float64 | ||
averageLossMax float64 | ||
lastLossReport time.Time | ||
|
||
maxAcknowledgedRate types.DataRate | ||
lastAcknowledgedRateReport time.Time | ||
bitrate types.DataRate | ||
averageLoss float64 | ||
inertia float64 | ||
decay float64 | ||
} | ||
|
||
func newLossBasedBWE() *lossBasedBandwidthEstimator { | ||
return &lossBasedBandwidthEstimator{ | ||
config: lossBasedBWEConfig{ | ||
lossWindow: 800 * time.Millisecond, | ||
maxLossWindow: 800 * time.Millisecond, | ||
maxAcknowledgedRateWindow: 800 * time.Millisecond, | ||
}, | ||
bitrate: 0, | ||
|
||
averageLoss: 0, | ||
maxAverageLoss: 0, | ||
averageLossMax: 0, | ||
lastLossReport: time.Time{}, | ||
|
||
maxAcknowledgedRate: 0, | ||
lastAcknowledgedRateReport: time.Time{}, | ||
inertia: 0.5, | ||
decay: 0.5, | ||
bitrate: 0, | ||
averageLoss: 0, | ||
} | ||
} | ||
|
||
func (e *lossBasedBandwidthEstimator) getEstimate(wantedRate types.DataRate) types.DataRate { | ||
if e.bitrate == 0 { | ||
if e.bitrate <= 0 { | ||
e.bitrate = wantedRate | ||
} | ||
|
||
fmt.Printf("maxAverageLoss=%v\n", e.maxAverageLoss) | ||
// Naive implementation using constants from IETF Draft | ||
// TODO(mathis): Make this more smart and configurable. (Smart here means | ||
// don't decrease too often and such things, see libwebrtc) | ||
if e.maxAverageLoss < 0.02 { | ||
e.bitrate = types.DataRate(1.05 * float64(e.bitrate)) | ||
} else if e.maxAverageLoss > 0.1 { | ||
e.bitrate = types.DataRate(float64(e.bitrate) * (1 - 0.5*e.maxAverageLoss)) | ||
} | ||
|
||
return e.bitrate | ||
} | ||
|
||
func (e *lossBasedBandwidthEstimator) updateLossStats(now time.Time, results []types.PacketResult) { | ||
func (e *lossBasedBandwidthEstimator) updateLossStats(results []types.PacketResult) { | ||
packetsLost := 0 | ||
for _, p := range results { | ||
if !p.Received { | ||
packetsLost++ | ||
} | ||
} | ||
fmt.Printf("lost %v packets\n", packetsLost) | ||
|
||
lossRatio := float64(packetsLost) / float64(len(results)) | ||
delta := deltaOrDefault(e.lastLossReport, now, time.Second) | ||
e.lastLossReport = now | ||
e.averageLoss = e.inertia*lossRatio + e.decay*(1-e.inertia)*e.averageLoss | ||
|
||
e.averageLoss += exponentialUpdate(delta, e.config.lossWindow) * (lossRatio - e.averageLoss) | ||
if e.averageLoss > e.maxAverageLoss { | ||
e.maxAverageLoss = e.averageLoss | ||
} else { | ||
e.maxAverageLoss += exponentialUpdate(delta, e.config.maxLossWindow) * (e.averageLoss - e.maxAverageLoss) | ||
} | ||
} | ||
|
||
func (e *lossBasedBandwidthEstimator) updateAcknowledgedBitrate(now time.Time, acknowledgedRate types.DataRate) { | ||
delta := deltaOrDefault(e.lastAcknowledgedRateReport, now, time.Second) | ||
if acknowledgedRate > e.maxAcknowledgedRate { | ||
e.maxAcknowledgedRate = acknowledgedRate | ||
} else { | ||
// TODO(mathis): Double check these type conversions | ||
e.maxAcknowledgedRate -= types.DataRate(exponentialUpdate(delta, e.config.maxAcknowledgedRateWindow) * float64(e.maxAcknowledgedRate-acknowledgedRate)) | ||
} | ||
} | ||
|
||
func exponentialUpdate(delta, window time.Duration) float64 { | ||
return (1.0 - math.Exp(float64(delta.Milliseconds())/-float64(window.Milliseconds()))) | ||
} | ||
|
||
func deltaOrDefault(last, now time.Time, defaultVal time.Duration) time.Duration { | ||
if last.IsZero() { | ||
return defaultVal | ||
// Naive implementation using constants from IETF Draft | ||
// TODO(mathis): Make this more smart and configurable. (Smart here means | ||
// don't decrease too often and such things, see libwebrtc) | ||
if e.averageLoss < 0.02 { | ||
e.bitrate = types.DataRate(1.05 * float64(e.bitrate)) | ||
} else if e.averageLoss > 0.1 { | ||
e.bitrate = types.DataRate(float64(e.bitrate) * (1 - 0.5*e.averageLoss)) | ||
} | ||
return now.Sub(last) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters