From 532a4ca20d41d3b0ef4d1775748bb5dbf6d62e8a Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 24 May 2022 11:50:31 -0400 Subject: [PATCH] Support publishing average loss rate This change exposes an API for reading the loss rate. --- pkg/cc/interceptor.go | 2 ++ pkg/gcc/send_side_bwe.go | 20 ++++++++++++++++++++ pkg/gcc/send_side_bwe_test.go | 2 ++ 3 files changed, 24 insertions(+) diff --git a/pkg/cc/interceptor.go b/pkg/cc/interceptor.go index 2576cbbb..1548f180 100644 --- a/pkg/cc/interceptor.go +++ b/pkg/cc/interceptor.go @@ -24,7 +24,9 @@ type BandwidthEstimator interface { AddStream(*interceptor.StreamInfo, interceptor.RTPWriter) interceptor.RTPWriter WriteRTCP([]rtcp.Packet, interceptor.Attributes) error GetTargetBitrate() int + GetLossRate() float64 OnTargetBitrateChange(f func(bitrate int)) + OnLossRateChange(f func(loss float64)) GetStats() map[string]interface{} Close() error } diff --git a/pkg/gcc/send_side_bwe.go b/pkg/gcc/send_side_bwe.go index eb4caae0..be2469cf 100644 --- a/pkg/gcc/send_side_bwe.go +++ b/pkg/gcc/send_side_bwe.go @@ -43,6 +43,7 @@ type SendSideBWE struct { feedbackAdapter *cc.FeedbackAdapter onTargetBitrateChange func(bitrate int) + onLossRateChange func(loss float64) lock sync.Mutex latestStats Stats @@ -164,6 +165,14 @@ func (e *SendSideBWE) GetTargetBitrate() int { return e.latestBitrate } +// GetLossRate returns the current packet loss rate in the range [0, 1]. +func (e *SendSideBWE) GetLossRate() float64 { + e.lossController.lock.Lock() + defer e.lossController.lock.Unlock() + + return e.lossController.averageLoss +} + // GetStats returns some internal statistics of the bandwidth estimator func (e *SendSideBWE) GetStats() map[string]interface{} { e.lock.Lock() @@ -188,6 +197,12 @@ func (e *SendSideBWE) OnTargetBitrateChange(f func(bitrate int)) { e.onTargetBitrateChange = f } +// OnLossRateChange sets the callback that is called when the packet loss +// rate changes +func (e *SendSideBWE) OnLossRateChange(f func(loss float64)) { + e.onLossRateChange = f +} + // isClosed returns true if SendSideBWE is closed func (e *SendSideBWE) isClosed() bool { select { @@ -227,6 +242,11 @@ func (e *SendSideBWE) onDelayUpdate(delayStats DelayStats) { go e.onTargetBitrateChange(bitrate) } + // in principle this could update more frequently but this is a convenient place to put this hook. + if e.latestStats.LossStats.AverageLoss != lossStats.AverageLoss && e.onLossRateChange != nil { + go e.onLossRateChange(lossStats.AverageLoss) + } + e.latestStats = Stats{ LossStats: lossStats, DelayStats: delayStats, diff --git a/pkg/gcc/send_side_bwe_test.go b/pkg/gcc/send_side_bwe_test.go index 39ce24c1..ad53f71c 100644 --- a/pkg/gcc/send_side_bwe_test.go +++ b/pkg/gcc/send_side_bwe_test.go @@ -70,6 +70,7 @@ func TestSendSideBWE(t *testing.T) { twccSender.BindRTCPWriter(m.twccResponder) require.Equal(t, latestBitrate, bwe.GetTargetBitrate()) + require.Equal(t, 0.0, bwe.GetLossRate()) require.NotEqual(t, 0, len(bwe.GetStats())) rtpWriter := bwe.AddStream(streamInfo, m) @@ -89,6 +90,7 @@ func TestSendSideBWE(t *testing.T) { // Sending a stream with zero loss and no RTT should increase estimate require.Less(t, latestBitrate, bwe.GetTargetBitrate()) + require.Equal(t, 0.0, bwe.GetLossRate()) } func TestSendSideBWE_ErrorOnWriteRTCPAtClosedState(t *testing.T) {