Configurable bandwidth estimation side (#298)

* Fix tests

Add back adding track to publishedTracks for testing purposes.

* WIP branch

* Don't know why merge from `master` did not catch this change.

* WIP commit

* Hook up all the bits for TWCC to work

* Fix typo

* WIP commit

* Catch up to latest API

* Move RTP/RTCP info config

* Instantiate GCC/TWCC interceptor only when in use

* comment SSBWE parts

* RTCP feedback in publisher config
This commit is contained in:
Raja Subramanian authored and GitHub committed 2021-12-30 20:09:03 +05:30
1 parent 6f84b36ccf
commit 107e7bbb39
8 files changed
+240 -77

No files matched your search

+3
View File
@@ -62,6 +62,9 @@ type RTCConfig struct {
// Throttle periods for pli/fir rtcp packets
PLIThrottle PLIThrottleConfig `yaml:"pli_throttle"`
// Which side runs bandwidth estimation
UseSendSideBWE bool `yaml:"send_side_bandwidth_estimation"`
}
type PLIThrottleConfig struct {
+65
View File
@@ -5,6 +5,7 @@ import (
"net"
"github.com/pion/ice/v2"
"github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3"
"github.com/livekit/livekit-server/pkg/config"
@@ -15,6 +16,7 @@ import (
const (
minUDPBufferSize = 5_000_000
defaultUDPBufferSize = 16_777_216
frameMarking = "urn:ietf:params:rtp-hdrext:framemarking"
)
type WebRTCConfig struct {
@@ -25,6 +27,8 @@ type WebRTCConfig struct {
UDPMux ice.UDPMux
UDPMuxConn *net.UDPConn
TCPMuxListener *net.TCPListener
Publisher DirectionConfig
Subscriber DirectionConfig
}
type ReceiverConfig struct {
@@ -32,6 +36,21 @@ type ReceiverConfig struct {
maxBitrate uint64
}
type RTPHeaderExtensionConfig struct {
Audio []string
Video []string
}
type RTCPFeedbackConfig struct {
Audio []webrtc.RTCPFeedback
Video []webrtc.RTCPFeedback
}
type DirectionConfig struct {
RTPHeaderExtension RTPHeaderExtensionConfig
RTCPFeedback RTCPFeedbackConfig
}
// number of packets to buffer up
const readBufferSize = 50
@@ -112,6 +131,50 @@ func NewWebRTCConfig(conf *config.Config, externalIP string) (*WebRTCConfig, err
}
s.SetNetworkTypes(networkTypes)
// publisher configuration
publisherConfig := DirectionConfig{
RTPHeaderExtension: RTPHeaderExtensionConfig{
Audio: []string{
sdp.SDESMidURI,
sdp.SDESRTPStreamIDURI,
sdp.AudioLevelURI,
},
Video: []string{
sdp.SDESMidURI,
sdp.SDESRTPStreamIDURI,
sdp.TransportCCURI,
frameMarking,
},
},
RTCPFeedback: RTCPFeedbackConfig{
Video: []webrtc.RTCPFeedback{
{Type: webrtc.TypeRTCPFBGoogREMB},
{Type: webrtc.TypeRTCPFBTransportCC},
{Type: webrtc.TypeRTCPFBCCM, Parameter: "fir"},
{Type: webrtc.TypeRTCPFBNACK},
{Type: webrtc.TypeRTCPFBNACK, Parameter: "pli"},
},
},
}
// subscriber configuration
subscriberConfig := DirectionConfig{
RTCPFeedback: RTCPFeedbackConfig{
Video: []webrtc.RTCPFeedback{
{Type: webrtc.TypeRTCPFBCCM, Parameter: "fir"},
{Type: webrtc.TypeRTCPFBNACK},
{Type: webrtc.TypeRTCPFBNACK, Parameter: "pli"},
},
},
}
if rtcConf.UseSendSideBWE {
subscriberConfig.RTPHeaderExtension.Video = append(subscriberConfig.RTPHeaderExtension.Video, sdp.TransportCCURI)
subscriberConfig.RTCPFeedback.Video = append(subscriberConfig.RTCPFeedback.Video, webrtc.RTCPFeedback{Type: webrtc.TypeRTCPFBTransportCC})
} else {
subscriberConfig.RTPHeaderExtension.Video = append(subscriberConfig.RTPHeaderExtension.Video, sdp.ABSSendTimeURI)
subscriberConfig.RTCPFeedback.Video = append(subscriberConfig.RTCPFeedback.Video, webrtc.RTCPFeedback{Type: webrtc.TypeRTCPFBGoogREMB})
}
return &WebRTCConfig{
Configuration: c,
SettingEngine: s,
@@ -122,6 +185,8 @@ func NewWebRTCConfig(conf *config.Config, externalIP string) (*WebRTCConfig, err
UDPMux: udpMux,
UDPMuxConn: udpMuxConn,
TCPMuxListener: tcpListener,
Publisher: publisherConfig,
Subscriber: subscriberConfig,
}, nil
}
+22 -48
View File
@@ -4,16 +4,11 @@ import (
"strings"
"github.com/livekit/protocol/livekit"
"github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3"
)
const (
frameMarking = "urn:ietf:params:rtp-hdrext:framemarking"
)
func registerCodecs(me *webrtc.MediaEngine, codecs []*livekit.Codec) error {
opusCodec := webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2, SDPFmtpLine: "minptime=10;useinbandfec=1", RTCPFeedback: nil}
func registerCodecs(me *webrtc.MediaEngine, codecs []*livekit.Codec, rtcpFeedback RTCPFeedbackConfig) error {
opusCodec := webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2, SDPFmtpLine: "minptime=10;useinbandfec=1", RTCPFeedback: rtcpFeedback.Audio}
if isCodecEnabled(codecs, opusCodec) {
if err := me.RegisterCodec(webrtc.RTPCodecParameters{
RTPCodecCapability: opusCodec,
@@ -23,34 +18,29 @@ func registerCodecs(me *webrtc.MediaEngine, codecs []*livekit.Codec) error {
}
}
videoRTCPFeedback := []webrtc.RTCPFeedback{
{Type: webrtc.TypeRTCPFBGoogREMB, Parameter: ""},
{Type: webrtc.TypeRTCPFBCCM, Parameter: "fir"},
{Type: webrtc.TypeRTCPFBNACK, Parameter: ""},
{Type: webrtc.TypeRTCPFBNACK, Parameter: "pli"}}
for _, codec := range []webrtc.RTPCodecParameters{
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8, ClockRate: 90000, RTCPFeedback: videoRTCPFeedback},
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8, ClockRate: 90000, RTCPFeedback: rtcpFeedback.Video},
PayloadType: 96,
},
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP9, ClockRate: 90000, SDPFmtpLine: "profile-id=0", RTCPFeedback: videoRTCPFeedback},
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP9, ClockRate: 90000, SDPFmtpLine: "profile-id=0", RTCPFeedback: rtcpFeedback.Video},
PayloadType: 98,
},
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP9, ClockRate: 90000, SDPFmtpLine: "profile-id=1", RTCPFeedback: videoRTCPFeedback},
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP9, ClockRate: 90000, SDPFmtpLine: "profile-id=1", RTCPFeedback: rtcpFeedback.Video},
PayloadType: 100,
},
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", RTCPFeedback: videoRTCPFeedback},
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", RTCPFeedback: rtcpFeedback.Video},
PayloadType: 125,
},
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f", RTCPFeedback: videoRTCPFeedback},
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f", RTCPFeedback: rtcpFeedback.Video},
PayloadType: 108,
},
{
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032", RTCPFeedback: videoRTCPFeedback},
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032", RTCPFeedback: rtcpFeedback.Video},
PayloadType: 123,
},
} {
@@ -63,46 +53,30 @@ func registerCodecs(me *webrtc.MediaEngine, codecs []*livekit.Codec) error {
return nil
}
func createPubMediaEngine(codecs []*livekit.Codec) (*webrtc.MediaEngine, error) {
me := &webrtc.MediaEngine{}
if err := registerCodecs(me, codecs); err != nil {
return nil, err
}
for _, extension := range []string{
sdp.SDESMidURI,
sdp.SDESRTPStreamIDURI,
sdp.TransportCCURI,
frameMarking,
} {
func registerHeaderExtensions(me *webrtc.MediaEngine, rtpHeaderExtension RTPHeaderExtensionConfig) error {
for _, extension := range rtpHeaderExtension.Video {
if err := me.RegisterHeaderExtension(webrtc.RTPHeaderExtensionCapability{URI: extension}, webrtc.RTPCodecTypeVideo); err != nil {
return nil, err
}
}
for _, extension := range []string{
sdp.SDESMidURI,
sdp.SDESRTPStreamIDURI,
sdp.AudioLevelURI,
} {
if err := me.RegisterHeaderExtension(webrtc.RTPHeaderExtensionCapability{URI: extension}, webrtc.RTPCodecTypeAudio); err != nil {
return nil, err
return err
}
}
return me, nil
for _, extension := range rtpHeaderExtension.Audio {
if err := me.RegisterHeaderExtension(webrtc.RTPHeaderExtensionCapability{URI: extension}, webrtc.RTPCodecTypeAudio); err != nil {
return err
}
}
return nil
}
func createSubMediaEngine(codecs []*livekit.Codec) (*webrtc.MediaEngine, error) {
func createMediaEngine(codecs []*livekit.Codec, config DirectionConfig) (*webrtc.MediaEngine, error) {
me := &webrtc.MediaEngine{}
if err := registerCodecs(me, codecs); err != nil {
if err := registerCodecs(me, codecs, config.RTCPFeedback); err != nil {
return nil, err
}
for _, extension := range []string{
sdp.ABSSendTimeURI,
} {
if err := me.RegisterHeaderExtension(webrtc.RTPHeaderExtensionCapability{URI: extension}, webrtc.RTPCodecTypeVideo); err != nil {
return nil, err
}
if err := registerHeaderExtensions(me, config.RTPHeaderExtension); err != nil {
return nil, err
}
return me, nil
+12 -8
View File
@@ -25,13 +25,6 @@ import (
"github.com/livekit/livekit-server/pkg/telemetry"
)
var (
FeedbackTypes = []webrtc.RTCPFeedback{
{Type: webrtc.TypeRTCPFBGoogREMB},
{Type: webrtc.TypeRTCPFBNACK},
{Type: webrtc.TypeRTCPFBNACK, Parameter: "pli"}}
)
const (
lostUpdateDelta = time.Second
connectionQualityUpdateInterval = 5 * time.Second
@@ -96,6 +89,8 @@ type MediaTrackParams struct {
AudioConfig config.AudioConfig
Telemetry telemetry.TelemetryService
Logger logger.Logger
SubscriberConfig DirectionConfig
}
func NewMediaTrack(track *webrtc.TrackRemote, params MediaTrackParams) *MediaTrack {
@@ -220,13 +215,22 @@ func (t *MediaTrack) AddSubscriber(sub types.Participant) error {
// react-native-webrtc still uses stream based APIs and require this
streamId = PackStreamID(t.params.ParticipantID, t.ID())
}
receiver := NewWrappedReceiver(t.receiver, t.ID(), streamId)
var rtcpFeedback []webrtc.RTCPFeedback
switch t.Kind() {
case livekit.TrackType_AUDIO:
rtcpFeedback = t.params.SubscriberConfig.RTCPFeedback.Audio
case livekit.TrackType_VIDEO:
rtcpFeedback = t.params.SubscriberConfig.RTCPFeedback.Video
}
downTrack, err := sfu.NewDownTrack(webrtc.RTPCodecCapability{
MimeType: codec.MimeType,
ClockRate: codec.ClockRate,
Channels: codec.Channels,
SDPFmtpLine: codec.SDPFmtpLine,
RTCPFeedback: FeedbackTypes,
RTCPFeedback: rtcpFeedback,
}, receiver, t.params.BufferFactory, subscriberID, t.params.ReceiverConfig.PacketBufferSize)
if err != nil {
return err
+60 -4
View File
@@ -7,6 +7,8 @@ import (
"github.com/bep/debounce"
"github.com/livekit/protocol/livekit"
"github.com/livekit/protocol/logger"
"github.com/pion/interceptor"
"github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3"
"github.com/livekit/livekit-server/pkg/rtc/types"
@@ -55,29 +57,78 @@ type TransportParams struct {
Logger logger.Logger
}
// LK-TODO-SSBWE func newPeerConnection(params TransportParams, onBandwidthEstimator func(estimator cc.BandwidthEstimator)) (*webrtc.PeerConnection, *webrtc.MediaEngine, error) {
func newPeerConnection(params TransportParams) (*webrtc.PeerConnection, *webrtc.MediaEngine, error) {
var me *webrtc.MediaEngine
var err error
var directionConfig DirectionConfig
if params.Target == livekit.SignalTarget_PUBLISHER {
me, err = createPubMediaEngine(params.EnabledCodecs)
directionConfig = params.Config.Publisher
} else {
me, err = createSubMediaEngine(params.EnabledCodecs)
directionConfig = params.Config.Subscriber
}
me, err := createMediaEngine(params.EnabledCodecs, directionConfig)
if err != nil {
return nil, nil, err
}
se := params.Config.SettingEngine
se.DisableMediaEngineCopy(true)
ir := &interceptor.Registry{}
if params.Target == livekit.SignalTarget_SUBSCRIBER {
isSendSideBWE := false
for _, ext := range directionConfig.RTPHeaderExtension.Video {
if ext == sdp.TransportCCURI {
isSendSideBWE = true
break
}
}
for _, ext := range directionConfig.RTPHeaderExtension.Audio {
if ext == sdp.TransportCCURI {
isSendSideBWE = true
break
}
}
if isSendSideBWE {
/* LK-TODO-SSBWE
gf, err := cc.NewInterceptor(func() (cc.BandwidthEstimator, error) {
return gcc.NewSendSideBWE(
gcc.SendSideBWEInitialBitrate(1*1000*1000),
gcc.SendSideBWEPacer(gcc.NewNoOpPacer()),
)
})
if err == nil {
gf.OnNewPeerConnection(func(id string, estimator cc.BandwidthEstimator) {
if onBandwidthEstimator != nil {
onBandwidthEstimator(estimator)
}
})
ir.Add(gf)
tf, err := twcc.NewHeaderExtensionInterceptor()
if err == nil {
ir.Add(tf)
}
}
*/
}
}
api := webrtc.NewAPI(
webrtc.WithMediaEngine(me),
webrtc.WithSettingEngine(se),
webrtc.WithInterceptorRegistry(ir),
)
pc, err := api.NewPeerConnection(params.Config.Configuration)
return pc, me, err
}
func NewPCTransport(params TransportParams) (*PCTransport, error) {
/* LK-TODO-SSBWE
var bwe cc.BandwidthEstimator
pc, me, err := newPeerConnection(params, func(estimator cc.BandwidthEstimator) {
bwe = estimator
})
*/
pc, me, err := newPeerConnection(params)
if err != nil {
return nil, err
@@ -95,6 +146,11 @@ func NewPCTransport(params TransportParams) (*PCTransport, error) {
Logger: params.Logger,
})
t.streamAllocator.Start()
/* LK-TODO-SSBWE
if bwe != nil {
t.streamAllocator.SetBandwidthEstimator(bwe)
}
*/
}
t.pc.OnICEGatheringStateChange(func(state webrtc.ICEGathererState) {
if state == webrtc.ICEGathererStateComplete {
+1
View File
@@ -342,6 +342,7 @@ func (u *UptrackManager) MediaTrackReceived(track *webrtc.TrackRemote, rtpReceiv
AudioConfig: u.params.AudioConfig,
Telemetry: u.params.Telemetry,
Logger: u.params.Logger,
SubscriberConfig: u.params.Config.Subscriber,
})
mt.OnSubscribedMaxQualityChange(u.onSubscribedMaxQualityChange)
+11 -2
View File
@@ -114,8 +114,9 @@ type DownTrack struct {
pktsDropped atomicUint32
// RTCP callbacks
onRTCP func([]rtcp.Packet)
onREMB func(dt *DownTrack, remb *rtcp.ReceiverEstimatedMaximumBitrate)
onRTCP func([]rtcp.Packet)
onREMB func(dt *DownTrack, remb *rtcp.ReceiverEstimatedMaximumBitrate)
onTransportCCFeedback func(dt *DownTrack, cc *rtcp.TransportLayerCC)
// simulcast layer availability change callback
onAvailableLayersChanged func(dt *DownTrack)
@@ -497,6 +498,10 @@ func (d *DownTrack) OnREMB(fn func(dt *DownTrack, remb *rtcp.ReceiverEstimatedMa
d.onREMB = fn
}
func (d *DownTrack) OnTransportCCFeedback(fn func(dt *DownTrack, cc *rtcp.TransportLayerCC)) {
d.onTransportCCFeedback = fn
}
func (d *DownTrack) CurrentMaxLossFraction() uint8 {
return d.lossFraction.get()
}
@@ -851,6 +856,10 @@ func (d *DownTrack) handleRTCP(bytes []byte) {
nackedPackets = append(nackedPackets, d.sequencer.getSeqNoPairs(pair.PacketList())...)
}
go d.retransmitPackets(nackedPackets)
case *rtcp.TransportLayerCC:
if p.MediaSSRC == d.ssrc && d.onTransportCCFeedback != nil {
d.onTransportCCFeedback(d, p)
}
}
}
}
+66 -15
View File
@@ -62,6 +62,7 @@ const (
SignalAddTrack Signal = iota
SignalRemoveTrack
SignalEstimate
SignalTargetBitrate
SignalReceiverReport
SignalAvailableLayersChange
SignalSubscriptionChange
@@ -78,6 +79,8 @@ func (s Signal) String() string {
return "REMOVE_TRACK"
case SignalEstimate:
return "ESTIMATE"
case SignalTargetBitrate:
return "TARGET_BITRATE"
case SignalReceiverReport:
return "RECEIVER_REPORT"
case SignalSubscriptionChange:
@@ -93,6 +96,16 @@ func (s Signal) String() string {
}
}
type Event struct {
Signal Signal
DownTrack *DownTrack
Data interface{}
}
func (e Event) String() string {
return fmt.Sprintf("StreamAllocator:Event{signal: %s, data: %s}", e.Signal, e.Data)
}
type StreamAllocatorParams struct {
Logger logger.Logger
}
@@ -102,7 +115,10 @@ type StreamAllocator struct {
onStreamStateChange func(update *StreamStateUpdate) error
trackingSSRC uint32
rembTrackingSSRC uint32
// LK-TODO-SSBWE bwe cc.BandwidthEstimator
committedChannelCapacity int64
lastCommitTime time.Time
prevReceivedEstimate int64
@@ -127,16 +143,6 @@ type StreamAllocator struct {
runningCh chan struct{}
}
type Event struct {
Signal Signal
DownTrack *DownTrack
Data interface{}
}
func (e Event) String() string {
return fmt.Sprintf("StreamAllocator:Event{signal: %s, data: %s}", e.Signal, e.Data)
}
func NewStreamAllocator(params StreamAllocatorParams) *StreamAllocator {
s := &StreamAllocator{
logger: params.Logger,
@@ -173,6 +179,15 @@ func (s *StreamAllocator) OnStreamStateChange(f func(update *StreamStateUpdate)
s.onStreamStateChange = f
}
/* LK-TODO-SSBWE
func (s *StreamAllocator) SetBandwidthEstimator(bwe cc.BandwidthEstimator) {
if bwe != nil {
bwe.OnTargetBitrateChange(s.onTargetBitrateChange)
}
s.bwe = bwe
}
*/
func (s *StreamAllocator) AddTrack(downTrack *DownTrack, isManaged bool) {
s.postEvent(Event{
Signal: SignalAddTrack,
@@ -182,6 +197,7 @@ func (s *StreamAllocator) AddTrack(downTrack *DownTrack, isManaged bool) {
if downTrack.Kind() == webrtc.RTPCodecTypeVideo {
downTrack.OnREMB(s.onREMB)
downTrack.OnTransportCCFeedback(s.onTransportCCFeedback)
downTrack.OnAvailableLayersChanged(s.onAvailableLayersChanged)
downTrack.OnSubscriptionChanged(s.onSubscriptionChanged)
downTrack.OnSubscribedLayersChanged(s.onSubscribedLayersChanged)
@@ -215,6 +231,23 @@ func (s *StreamAllocator) onREMB(downTrack *DownTrack, remb *rtcp.ReceiverEstima
})
}
// called when a new transport-cc feedback is received
func (s *StreamAllocator) onTransportCCFeedback(downTrack *DownTrack, fb *rtcp.TransportLayerCC) {
/* LK-TODO-SSBWE
if s.bwe != nil {
s.bwe.WriteRTCP([]rtcp.Packet{fb}, nil)
}
*/
}
// called when target bitrate changes
func (s *StreamAllocator) onTargetBitrateChange(bitrate int) {
s.postEvent(Event{
Signal: SignalTargetBitrate,
Data: bitrate,
})
}
// called when a new RTCP Receiver Report is received
func (s *StreamAllocator) onReceiverReport(downTrack *DownTrack, rr *rtcp.ReceiverReport) {
s.postEvent(Event{
@@ -311,6 +344,8 @@ func (s *StreamAllocator) handleEvent(event *Event) {
s.handleSignalRemoveTrack(event)
case SignalEstimate:
s.handleSignalEstimate(event)
case SignalTargetBitrate:
s.handleSignalTargetBitrate(event)
case SignalReceiverReport:
s.handleSignalReceiverReport(event)
case SignalAvailableLayersChange:
@@ -428,7 +463,7 @@ func (s *StreamAllocator) handleSignalEstimate(event *Event) {
found := false
for _, ssrc := range remb.SSRCs {
if ssrc == s.trackingSSRC {
if ssrc == s.rembTrackingSSRC {
found = true
break
}
@@ -442,18 +477,18 @@ func (s *StreamAllocator) handleSignalEstimate(event *Event) {
// try to lock to track which is sending this update
for _, ssrc := range remb.SSRCs {
if ssrc == event.DownTrack.SSRC() {
s.trackingSSRC = event.DownTrack.SSRC()
s.rembTrackingSSRC = event.DownTrack.SSRC()
found = true
break
}
}
if !found {
s.trackingSSRC = remb.SSRCs[0]
s.rembTrackingSSRC = remb.SSRCs[0]
}
}
if s.trackingSSRC != event.DownTrack.SSRC() {
if s.rembTrackingSSRC != event.DownTrack.SSRC() {
return
}
@@ -473,6 +508,22 @@ func (s *StreamAllocator) handleSignalEstimate(event *Event) {
}
}
func (s *StreamAllocator) handleSignalTargetBitrate(event *Event) {
receivedEstimate, _ := event.Data.(int)
s.prevReceivedEstimate = s.receivedEstimate
s.receivedEstimate = int64(receivedEstimate)
if s.prevReceivedEstimate != s.receivedEstimate {
s.logger.Debugw("received new estimate",
"old(bps)", s.prevReceivedEstimate,
"new(bps)", s.receivedEstimate,
)
}
if s.maybeCommitEstimate() {
s.allocateAllTracks()
}
}
// LK-TODO-START
// Receiver report stats are not used in the current implementation.
//