Commit 48a9b10c authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Use spatial scalability when simulcast is not available.

If the client requested a low-resolution stream and there is none,
switch to SID=0.
parent 4f7be196
...@@ -129,8 +129,12 @@ func (down *rtpDownTrack) SetCname(cname string) { ...@@ -129,8 +129,12 @@ func (down *rtpDownTrack) SetCname(cname string) {
} }
type layerInfo struct { type layerInfo struct {
// current sid, desired sid, and max sid seen
sid, wantedSid, maxSid uint8 sid, wantedSid, maxSid uint8
// current tid, desired tid, and max tid seen
tid, wantedTid, maxTid uint8 tid, wantedTid, maxTid uint8
// if true, stick to sid 0
limitSid bool
} }
func (down *rtpDownTrack) getLayerInfo() layerInfo { func (down *rtpDownTrack) getLayerInfo() layerInfo {
...@@ -139,6 +143,7 @@ func (down *rtpDownTrack) getLayerInfo() layerInfo { ...@@ -139,6 +143,7 @@ func (down *rtpDownTrack) getLayerInfo() layerInfo {
sid: uint8((info & 0xF)), sid: uint8((info & 0xF)),
wantedSid: uint8((info >> 4) & 0xF), wantedSid: uint8((info >> 4) & 0xF),
maxSid: uint8((info >> 8) & 0xF), maxSid: uint8((info >> 8) & 0xF),
limitSid: ((info >> 12) & 1) != 0,
tid: uint8((info >> 16) & 0xF), tid: uint8((info >> 16) & 0xF),
wantedTid: uint8((info >> 20) & 0xF), wantedTid: uint8((info >> 20) & 0xF),
maxTid: uint8((info >> 24) & 0xF), maxTid: uint8((info >> 24) & 0xF),
...@@ -146,10 +151,15 @@ func (down *rtpDownTrack) getLayerInfo() layerInfo { ...@@ -146,10 +151,15 @@ func (down *rtpDownTrack) getLayerInfo() layerInfo {
} }
func (down *rtpDownTrack) setLayerInfo(info layerInfo) { func (down *rtpDownTrack) setLayerInfo(info layerInfo) {
var l uint32
if info.limitSid {
l = 1 << 12
}
atomic.StoreUint32(&down.atomics.layerInfo, atomic.StoreUint32(&down.atomics.layerInfo,
uint32(info.sid&0xF)| uint32(info.sid&0xF)|
uint32(info.wantedSid&0xF)<<4| uint32(info.wantedSid&0xF)<<4|
uint32(info.maxSid&0xF)<<8| uint32(info.maxSid&0xF)<<8|
l|
uint32(info.tid&0xF)<<16| uint32(info.tid&0xF)<<16|
uint32(info.wantedTid&0xF)<<20| uint32(info.wantedTid&0xF)<<20|
uint32(info.maxTid&0xF)<<24, uint32(info.maxTid&0xF)<<24,
...@@ -221,6 +231,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) { ...@@ -221,6 +231,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) {
layer := down.getLayerInfo() layer := down.getLayerInfo()
// increase eagerly if this is the first time we see a given layer
if flags.Tid > layer.maxTid || flags.Sid > layer.maxSid { if flags.Tid > layer.maxTid || flags.Sid > layer.maxSid {
if flags.Tid > layer.maxTid { if flags.Tid > layer.maxTid {
if layer.tid == layer.maxTid { if layer.tid == layer.maxTid {
...@@ -230,7 +241,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) { ...@@ -230,7 +241,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) {
layer.maxTid = flags.Tid layer.maxTid = flags.Tid
} }
if flags.Sid > layer.maxSid { if flags.Sid > layer.maxSid {
if layer.sid == layer.maxSid { if layer.sid == layer.maxSid && !layer.limitSid {
layer.wantedSid = flags.Sid layer.wantedSid = flags.Sid
layer.sid = flags.Sid layer.sid = flags.Sid
} }
...@@ -240,6 +251,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) { ...@@ -240,6 +251,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) {
down.adjustLayer() down.adjustLayer()
layer = down.getLayerInfo() layer = down.getLayerInfo()
} }
if flags.Start && (layer.tid != layer.wantedTid) { if flags.Start && (layer.tid != layer.wantedTid) {
if layer.wantedTid < layer.tid || flags.TidUpSync { if layer.wantedTid < layer.tid || flags.TidUpSync {
layer.tid = layer.wantedTid layer.tid = layer.wantedTid
...@@ -331,7 +343,10 @@ func (t *rtpDownTrack) adjustLayer() { ...@@ -331,7 +343,10 @@ func (t *rtpDownTrack) adjustLayer() {
if rate < max*7/8 { if rate < max*7/8 {
// switch up // switch up
layer := t.getLayerInfo() layer := t.getLayerInfo()
if layer.sid < layer.maxSid { if layer.limitSid && layer.wantedSid != 0 {
layer.wantedSid = 0
t.setLayerInfo(layer)
} else if !layer.limitSid && layer.sid < layer.maxSid {
layer.wantedSid = layer.sid + 1 layer.wantedSid = layer.sid + 1
t.setLayerInfo(layer) t.setLayerInfo(layer)
} else if layer.tid < layer.maxTid { } else if layer.tid < layer.maxTid {
...@@ -345,7 +360,11 @@ func (t *rtpDownTrack) adjustLayer() { ...@@ -345,7 +360,11 @@ func (t *rtpDownTrack) adjustLayer() {
layer.wantedTid = layer.tid - 1 layer.wantedTid = layer.tid - 1
t.setLayerInfo(layer) t.setLayerInfo(layer)
} else if layer.sid > 0 { } else if layer.sid > 0 {
layer.wantedSid = layer.sid - 1 if layer.limitSid {
layer.wantedSid = 0
} else {
layer.wantedSid = layer.sid - 1
}
t.setLayerInfo(layer) t.setLayerInfo(layer)
} }
} }
......
...@@ -18,7 +18,7 @@ func TestDownTrackAtomics(t *testing.T) { ...@@ -18,7 +18,7 @@ func TestDownTrackAtomics(t *testing.T) {
down.setSRTime(4, 5) down.setSRTime(4, 5)
down.maxBitrate.Set(6, rtptime.Jiffies()) down.maxBitrate.Set(6, rtptime.Jiffies())
down.maxREMBBitrate.Set(7, rtptime.Jiffies()) down.maxREMBBitrate.Set(7, rtptime.Jiffies())
info := layerInfo{8, 9, 10, 11, 12, 13} info := layerInfo{8, 9, 10, 11, 12, 13, true}
down.setLayerInfo(info) down.setLayerInfo(info)
ntp, rtp := down.getTimeOffset() ntp, rtp := down.getTimeOffset()
rtt := down.getRTT() rtt := down.getRTT()
......
...@@ -446,7 +446,7 @@ func delDownTrackUnlocked(conn *rtpDownConnection, track *rtpDownTrack) error { ...@@ -446,7 +446,7 @@ func delDownTrackUnlocked(conn *rtpDownConnection, track *rtpDownTrack) error {
return os.ErrNotExist return os.ErrNotExist
} }
func replaceTracks(conn *rtpDownConnection, remote []conn.UpTrack) (bool, error) { func replaceTracks(conn *rtpDownConnection, remote []conn.UpTrack, limitSid bool) (bool, error) {
conn.mu.Lock() conn.mu.Lock()
defer conn.mu.Unlock() defer conn.mu.Unlock()
...@@ -489,6 +489,17 @@ outer2: ...@@ -489,6 +489,17 @@ outer2:
del = append(del, track) del = append(del, track)
} }
defer func() {
for _, t := range conn.tracks {
layer := t.getLayerInfo()
layer.limitSid = limitSid
if limitSid {
layer.wantedSid = 0
}
t.setLayerInfo(layer)
}
}()
if len(del) == 0 && len(add) == 0 { if len(del) == 0 && len(add) == 0 {
return false, nil return false, nil
} }
...@@ -729,7 +740,7 @@ func requestConns(target group.Client, g *group.Group, id string) { ...@@ -729,7 +740,7 @@ func requestConns(target group.Client, g *group.Group, id string) {
} }
} }
func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn.UpTrack) []conn.UpTrack { func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn.UpTrack) ([]conn.UpTrack, bool) {
r := override r := override
if r == nil { if r == nil {
var ok bool var ok bool
...@@ -738,7 +749,7 @@ func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn. ...@@ -738,7 +749,7 @@ func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn.
r, ok = c.requested[""] r, ok = c.requested[""]
} }
if !ok || len(r) == 0 { if !ok || len(r) == 0 {
return nil return nil, false
} }
} }
...@@ -777,6 +788,7 @@ func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn. ...@@ -777,6 +788,7 @@ func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn.
} }
var ts []conn.UpTrack var ts []conn.UpTrack
limitSid := false
if audio { if audio {
t := find(webrtc.RTPCodecTypeAudio) t := find(webrtc.RTPCodecTypeAudio)
if t != nil { if t != nil {
...@@ -796,10 +808,13 @@ func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn. ...@@ -796,10 +808,13 @@ func requestedTracks(c *webClient, override []string, up conn.Up, tracks []conn.
) )
if t != nil { if t != nil {
ts = append(ts, t) ts = append(ts, t)
if t.Label() != "l" {
limitSid = true
}
} }
} }
return ts return ts, limitSid
} }
func (c *webClient) PushConn(g *group.Group, id string, up conn.Up, tracks []conn.UpTrack, replace string) error { func (c *webClient) PushConn(g *group.Group, id string, up conn.Up, tracks []conn.UpTrack, replace string) error {
...@@ -991,6 +1006,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error { ...@@ -991,6 +1006,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, replace string) error { func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, replace string) error {
var requested []conn.UpTrack var requested []conn.UpTrack
limitSid := false
if up != nil { if up != nil {
var old *rtpDownConnection var old *rtpDownConnection
if replace != "" { if replace != "" {
...@@ -1002,7 +1018,7 @@ func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, re ...@@ -1002,7 +1018,7 @@ func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, re
if old != nil { if old != nil {
override = old.requested override = old.requested
} }
requested = requestedTracks(c, override, up, tracks) requested, limitSid = requestedTracks(c, override, up, tracks)
} }
if replace != "" { if replace != "" {
...@@ -1031,7 +1047,7 @@ func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, re ...@@ -1031,7 +1047,7 @@ func pushDownConn(c *webClient, id string, up conn.Up, tracks []conn.UpTrack, re
} }
return err return err
} }
done, err := replaceTracks(down, requested) done, err := replaceTracks(down, requested, limitSid)
if err != nil || !done { if err != nil || !done {
return err return err
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment