Files
livekit/pkg/rtc/subscribedtrack.go
Raja Subramanian 1dcc62b569 SubscribedQualityUpdate message (#270)
* WIP commit

* SubscribedQualityUpdate message to send list of currently subscribed
qualities for a simulcast video publisher

* Correct subscriberID

* goimports

* Do quality update on add/remove of subscribed track

* do not update quality when admin mute is active

* update quality on admin unmute

* Update protocol version

* Simplify max subscribed quality loop per David's suggestion
2021-12-19 12:41:40 +05:30

133 lines
3.1 KiB
Go

package rtc
import (
"sync/atomic"
"time"
"github.com/bep/debounce"
"github.com/livekit/protocol/livekit"
"github.com/livekit/protocol/utils"
"github.com/pion/webrtc/v3"
"github.com/livekit/livekit-server/pkg/rtc/types"
"github.com/livekit/livekit-server/pkg/sfu"
)
const (
subscriptionDebounceInterval = 100 * time.Millisecond
)
type SubscribedTrack struct {
publishedTrack types.MediaTrack
dt *sfu.DownTrack
publisherIdentity string
subscriberID string
subMuted utils.AtomicFlag
pubMuted utils.AtomicFlag
settings atomic.Value // *livekit.UpdateTrackSettings
onBind func()
debouncer func(func())
}
func NewSubscribedTrack(mediaTrack types.MediaTrack, publisherIdentity string, subscriberID string, dt *sfu.DownTrack) *SubscribedTrack {
return &SubscribedTrack{
publishedTrack: mediaTrack,
publisherIdentity: publisherIdentity,
subscriberID: subscriberID,
dt: dt,
debouncer: debounce.New(subscriptionDebounceInterval),
}
}
func (t *SubscribedTrack) OnBind(f func()) {
t.onBind = f
}
func (t *SubscribedTrack) Bound() {
if t.onBind != nil {
t.onBind()
}
}
func (t *SubscribedTrack) ID() string {
return t.dt.ID()
}
func (t *SubscribedTrack) PublisherIdentity() string {
return t.publisherIdentity
}
func (t *SubscribedTrack) DownTrack() *sfu.DownTrack {
return t.dt
}
func (t *SubscribedTrack) PublishedTrack() types.MediaTrack {
return t.publishedTrack
}
func (t *SubscribedTrack) SubscribeLossPercentage() uint32 {
return FixedPointToPercent(t.DownTrack().CurrentMaxLossFraction())
}
// has subscriber indicated it wants to mute this track
func (t *SubscribedTrack) IsMuted() bool {
return t.subMuted.Get()
}
func (t *SubscribedTrack) SetPublisherMuted(muted bool) {
t.pubMuted.TrySet(muted)
t.updateDownTrackMute()
}
func (t *SubscribedTrack) UpdateSubscriberSettings(settings *livekit.UpdateTrackSettings) {
visibilityChanged := t.subMuted.TrySet(settings.Disabled)
t.settings.Store(settings)
// avoid frequent changes to mute & video layers, unless it became visible
if visibilityChanged && !settings.Disabled {
t.UpdateVideoLayer()
} else {
t.debouncer(t.UpdateVideoLayer)
}
}
func (t *SubscribedTrack) UpdateVideoLayer() {
t.updateDownTrackMute()
if t.dt.Kind() != webrtc.RTPCodecTypeVideo {
return
}
if t.subMuted.Get() {
t.publishedTrack.NotifySubscriberMute(t.subscriberID)
return
}
settings, ok := t.settings.Load().(*livekit.UpdateTrackSettings)
if !ok {
return
}
quality := settings.Quality
if settings.Width > 0 {
quality = t.publishedTrack.GetQualityForDimension(settings.Width, settings.Height)
}
t.dt.SetMaxSpatialLayer(spatialLayerForQuality(quality))
t.publishedTrack.NotifySubscriberMaxQuality(t.subscriberID, quality)
}
func (t *SubscribedTrack) updateDownTrackMute() {
muted := t.subMuted.Get() || t.pubMuted.Get()
t.dt.Mute(muted)
}
func spatialLayerForQuality(quality livekit.VideoQuality) int32 {
switch quality {
case livekit.VideoQuality_LOW:
return 0
case livekit.VideoQuality_MEDIUM:
return 1
default:
return 2
}
}