Files
livekit/pkg/rtc/subscribedtrack.go
shishirng cb9f0d37c2 Use rtcscore-go to calculate audio/video score (#689)
* Use rtcscore-go to calculate audio/video score

Signed-off-by: shishir gowda <shishir@livekit.io>

* Get max expected layer and find max actual layer from stream

Signed-off-by: shishir gowda <shishir@livekit.io>

* Cleanup unused methods

Signed-off-by: shishir gowda <shishir@livekit.io>

* Cleanup code - address review comments

Signed-off-by: shishir gowda <shishir@livekit.io>

* get expected layer info instead of just quality

Signed-off-by: shishir gowda <shishir@livekit.io>

* Move SpatialLayerForQuality to utils/helpers

method is required in rtc,sfu and connectionstats pkg
Moved to utils/helpers.go to remove cyclic deps

Signed-off-by: shishir gowda <shishir@livekit.io>

* update tests

Signed-off-by: shishir gowda <shishir@livekit.io>

* Pick stream stats with max layer

Signed-off-by: shishir gowda <shishir@livekit.io>

* Update rtcscore-go pkg to make rtt/jitter optional

when passing 0, rtcscore-go was setting default values

Signed-off-by: shishir gowda <shishir@livekit.io>

* update score to rating

Signed-off-by: shishir gowda <shishir@livekit.io>

* Update rtcscore-go pkg to use simulcast layer info for score

Signed-off-by: shishir gowda <shishir@livekit.io>

* Update score ratings to reflect rtcscore range

Signed-off-by: shishir gowda <shishir@livekit.io>

* update test params for new rtcscore

Signed-off-by: shishir gowda <shishir@livekit.io>

* Delay sending scores to connections only till full data is available

first interval can have partial data leading to lower scores

Signed-off-by: shishir gowda <shishir@livekit.io>

* Check for inf values in quality params

Signed-off-by: shishir gowda <shishir@livekit.io>

* Clean up initial score calculation. Default to 5

Signed-off-by: shishir gowda <shishir@livekit.io>

Co-authored-by: David Zhao <dz@livekit.io>
2022-05-27 14:58:26 -04:00

135 lines
3.2 KiB
Go

package rtc
import (
"time"
"github.com/bep/debounce"
"github.com/pion/webrtc/v3"
"go.uber.org/atomic"
"github.com/livekit/protocol/livekit"
"github.com/livekit/livekit-server/pkg/rtc/types"
"github.com/livekit/livekit-server/pkg/sfu"
"github.com/livekit/livekit-server/pkg/utils"
)
const (
subscriptionDebounceInterval = 100 * time.Millisecond
)
type SubscribedTrackParams struct {
PublisherID livekit.ParticipantID
PublisherIdentity livekit.ParticipantIdentity
SubscriberID livekit.ParticipantID
SubscriberIdentity livekit.ParticipantIdentity
MediaTrack types.MediaTrack
DownTrack *sfu.DownTrack
AdaptiveStream bool
}
type SubscribedTrack struct {
params SubscribedTrackParams
subMuted atomic.Bool
pubMuted atomic.Bool
settings atomic.Value // *livekit.UpdateTrackSettings
onBind func()
debouncer func(func())
}
func NewSubscribedTrack(params SubscribedTrackParams) *SubscribedTrack {
s := &SubscribedTrack{
params: params,
debouncer: debounce.New(subscriptionDebounceInterval),
}
return s
}
func (t *SubscribedTrack) OnBind(f func()) {
t.onBind = f
}
func (t *SubscribedTrack) Bound() {
if !t.params.AdaptiveStream {
t.params.DownTrack.SetMaxSpatialLayer(utils.SpatialLayerForQuality(livekit.VideoQuality_HIGH))
}
if t.onBind != nil {
t.onBind()
}
}
func (t *SubscribedTrack) ID() livekit.TrackID {
return livekit.TrackID(t.params.DownTrack.ID())
}
func (t *SubscribedTrack) PublisherID() livekit.ParticipantID {
return t.params.PublisherID
}
func (t *SubscribedTrack) PublisherIdentity() livekit.ParticipantIdentity {
return t.params.PublisherIdentity
}
func (t *SubscribedTrack) SubscriberID() livekit.ParticipantID {
return t.params.SubscriberID
}
func (t *SubscribedTrack) SubscriberIdentity() livekit.ParticipantIdentity {
return t.params.SubscriberIdentity
}
func (t *SubscribedTrack) DownTrack() *sfu.DownTrack {
return t.params.DownTrack
}
func (t *SubscribedTrack) MediaTrack() types.MediaTrack {
return t.params.MediaTrack
}
// has subscriber indicated it wants to mute this track
func (t *SubscribedTrack) IsMuted() bool {
return t.subMuted.Load()
}
func (t *SubscribedTrack) SetPublisherMuted(muted bool) {
t.pubMuted.Store(muted)
t.updateDownTrackMute()
}
func (t *SubscribedTrack) UpdateSubscriberSettings(settings *livekit.UpdateTrackSettings) {
prevDisabled := t.subMuted.Swap(settings.Disabled)
t.settings.Store(settings)
// avoid frequent changes to mute & video layers, unless it became visible
if prevDisabled != settings.Disabled && !settings.Disabled {
t.UpdateVideoLayer()
} else {
t.debouncer(t.UpdateVideoLayer)
}
}
func (t *SubscribedTrack) UpdateVideoLayer() {
t.updateDownTrackMute()
if t.DownTrack().Kind() != webrtc.RTPCodecTypeVideo {
return
}
settings, ok := t.settings.Load().(*livekit.UpdateTrackSettings)
if !ok {
return
}
quality := settings.Quality
if settings.Width > 0 {
quality = t.MediaTrack().GetQualityForDimension(settings.Width, settings.Height)
}
t.DownTrack().SetMaxSpatialLayer(utils.SpatialLayerForQuality(quality))
}
func (t *SubscribedTrack) updateDownTrackMute() {
muted := t.subMuted.Load() || t.pubMuted.Load()
t.DownTrack().Mute(muted)
}