Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/relay #10

Merged
merged 13 commits into from
Nov 22, 2023
67 changes: 52 additions & 15 deletions bitratecontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/golang/glog"
"github.com/pion/interceptor/pkg/cc"
"github.com/pion/webrtc/v3"
)

Expand Down Expand Up @@ -69,19 +70,22 @@ func (c *bitrateClaim) pushbackDelayCounter() {
}

type bitrateController struct {
mu sync.RWMutex
client *Client
claims map[string]*bitrateClaim
mu sync.RWMutex
lastBitrateAdjustmentTS time.Time
client *Client
claims map[string]*bitrateClaim
}

func newbitrateController(client *Client, intervalMonitor time.Duration) *bitrateController {
func newbitrateController(client *Client, intervalMonitor time.Duration, useBandwidthEstimation bool) *bitrateController {
bc := &bitrateController{
mu: sync.RWMutex{},
client: client,
claims: make(map[string]*bitrateClaim, 0),
}

bc.start()
if !useBandwidthEstimation {
bc.start()
}

return bc
}
Expand Down Expand Up @@ -244,6 +248,7 @@ func (bc *bitrateController) addAudioClaims(clientTracks []iClientTrack) (leftTr
return leftTracks, nil
}

// this should never return QualityNone becaus it will delay onTrack event
func (bc *bitrateController) getDistributedQuality(totalTracks int) QualityLevel {
if totalTracks == 0 {
return 0
Expand All @@ -255,9 +260,7 @@ func (bc *bitrateController) getDistributedQuality(totalTracks int) QualityLevel

bitrateConfig := bc.client.SFU().bitratesConfig

if distributedBandwidth < bitrateConfig.VideoLow {
return QualityNone
} else if distributedBandwidth < bitrateConfig.VideoMid {
if distributedBandwidth < bitrateConfig.VideoMid {
return QualityLow
} else if distributedBandwidth < bitrateConfig.VideoHigh {
return QualityMid
Expand All @@ -281,10 +284,6 @@ func (bc *bitrateController) addClaims(clientTracks []iClientTrack) error {
for _, clientTrack := range leftTracks {
if clientTrack.Kind() == webrtc.RTPCodecTypeVideo {
trackQuality := bc.getDistributedQuality(len(leftTracks) - claimed)
if clientTrack.IsScreen() && trackQuality == QualityNone {
trackQuality = QualityLow
}

if _, ok := bc.claims[clientTrack.ID()]; ok {
errors = append(errors, ErrAlreadyClaimed)
continue
Expand All @@ -298,7 +297,7 @@ func (bc *bitrateController) addClaims(clientTracks []iClientTrack) error {
if clientTrack.IsSimulcast() {
clientTrack.(*simulcastClientTrack).lastQuality.Store(uint32(trackQuality))
} else if clientTrack.IsScaleable() {
clientTrack.(*scaleabletClientTrack).lastQuality = trackQuality
clientTrack.(*scaleableClientTrack).lastQuality = trackQuality
}

_, err := bc.addClaim(clientTrack, trackQuality, true)
Expand Down Expand Up @@ -332,10 +331,16 @@ func (bc *bitrateController) addClaim(clientTrack iClientTrack, quality QualityL
bitrate: bitrate,
}

clientTrack.OnTrackEnded(func() {
go func() {
ctx, cancel := context.WithCancel(clientTrack.Context())
defer cancel()
<-ctx.Done()
bc.removeClaim(clientTrack.ID())
if bc.client.IsDebugEnabled() {
glog.Info("clienttrack: track ", clientTrack.ID(), " claim removed")
}
clientTrack.Client().stats.removeSenderStats(clientTrack.ID())
})
}()

return bc.claims[clientTrack.ID()], nil
}
Expand All @@ -345,6 +350,7 @@ func (bc *bitrateController) removeClaim(id string) {
defer bc.mu.Unlock()

if _, ok := bc.claims[id]; !ok {
glog.Error("bitrate: track ", id, " is not exists")
return
}

Expand Down Expand Up @@ -440,6 +446,37 @@ func (bc *bitrateController) start() {
}()
}

func (bc *bitrateController) needIncreaseBitrate(availableBw uint32) bool {
claims := bc.Claims()

for _, claim := range claims {
if claim.quality < QualityHigh {
if bc.isEnoughBandwidthToIncrase(availableBw, claim) {
return true
}
}
}

return false
}

func (bc *bitrateController) MonitorBandwidth(estimator cc.BandwidthEstimator) {
estimator.OnTargetBitrateChange(func(bw int) {

availableBw := uint32(bw) - bc.totalSentBitrates()

if bc.totalSentBitrates() > uint32(bw) || (bc.totalSentBitrates() < uint32(bw) && bc.needIncreaseBitrate(availableBw)) {
if time.Since(bc.lastBitrateAdjustmentTS) > 500*time.Millisecond {
glog.Info("brcontroller: target bitrate changed to ", ThousandSeparator(bw), ", will check and adjust bitrates")

bc.checkAndAdjustBitrates()

bc.lastBitrateAdjustmentTS = time.Now()
}
}
})
}

// checkAndAdjustBitrates will check if the available bandwidth is enough to send the current bitrate
// if not then it will try to reduce one by one of simulcast track quality until it fit the bandwidth
// if the bandwidth is enough to send the current bitrate, then it will try to increase the bitrate
Expand Down
Loading