mirror of
https://github.com/jech/galene.git
synced 2024-11-09 18:25:58 +01:00
Include jitter and delay in receiver reports.
This commit is contained in:
parent
7961d7279b
commit
4dd245712f
4 changed files with 114 additions and 10 deletions
20
client.go
20
client.go
|
@ -18,6 +18,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sfu/estimator"
|
"sfu/estimator"
|
||||||
|
"sfu/jitter"
|
||||||
"sfu/mono"
|
"sfu/mono"
|
||||||
"sfu/packetcache"
|
"sfu/packetcache"
|
||||||
|
|
||||||
|
@ -294,6 +295,7 @@ func addUpConn(c *client, id string) (*upConnection, error) {
|
||||||
track: remote,
|
track: remote,
|
||||||
cache: packetcache.New(96),
|
cache: packetcache.New(96),
|
||||||
rate: estimator.New(time.Second),
|
rate: estimator.New(time.Second),
|
||||||
|
jitter: jitter.New(remote.Codec().ClockRate),
|
||||||
maxBitrate: ^uint64(0),
|
maxBitrate: ^uint64(0),
|
||||||
}
|
}
|
||||||
u.tracks = append(u.tracks, track)
|
u.tracks = append(u.tracks, track)
|
||||||
|
@ -343,6 +345,8 @@ func upLoop(conn *upConnection, track *upTrack) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
track.jitter.Accumulate(packet.Timestamp)
|
||||||
|
|
||||||
first := track.cache.Store(packet.SequenceNumber, buf[:bytes])
|
first := track.cache.Store(packet.SequenceNumber, buf[:bytes])
|
||||||
if packet.SequenceNumber-first > 24 {
|
if packet.SequenceNumber-first > 24 {
|
||||||
first, bitmap := track.cache.BitmapGet()
|
first, bitmap := track.cache.BitmapGet()
|
||||||
|
@ -379,6 +383,8 @@ func rtcpUpListener(conn *upConnection, track *upTrack, r *webrtc.RTPReceiver) {
|
||||||
case *rtcp.SenderReport:
|
case *rtcp.SenderReport:
|
||||||
atomic.StoreUint32(&track.lastSenderReport,
|
atomic.StoreUint32(&track.lastSenderReport,
|
||||||
uint32(p.NTPTime>>16))
|
uint32(p.NTPTime>>16))
|
||||||
|
atomic.StoreUint32(&track.lastSenderReportTime,
|
||||||
|
uint32(mono.Now(0x10000)))
|
||||||
case *rtcp.SourceDescription:
|
case *rtcp.SourceDescription:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,7 +398,7 @@ func sendRR(c *client, conn *upConnection) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ssrc := conn.tracks[0].track.SSRC()
|
now := uint32(mono.Now(0x10000))
|
||||||
|
|
||||||
reports := make([]rtcp.ReceptionReport, 0, len(conn.tracks))
|
reports := make([]rtcp.ReceptionReport, 0, len(conn.tracks))
|
||||||
for _, t := range conn.tracks {
|
for _, t := range conn.tracks {
|
||||||
|
@ -403,19 +409,24 @@ func sendRR(c *client, conn *upConnection) error {
|
||||||
if lost >= expected {
|
if lost >= expected {
|
||||||
lost = expected - 1
|
lost = expected - 1
|
||||||
}
|
}
|
||||||
|
lastSR := atomic.LoadUint32(&t.lastSenderReport)
|
||||||
|
delay := now - atomic.LoadUint32(&t.lastSenderReportTime)
|
||||||
|
|
||||||
reports = append(reports, rtcp.ReceptionReport{
|
reports = append(reports, rtcp.ReceptionReport{
|
||||||
SSRC: t.track.SSRC(),
|
SSRC: t.track.SSRC(),
|
||||||
LastSenderReport: atomic.LoadUint32(&t.lastSenderReport),
|
|
||||||
FractionLost: uint8((lost * 256) / expected),
|
FractionLost: uint8((lost * 256) / expected),
|
||||||
TotalLost: totalLost,
|
TotalLost: totalLost,
|
||||||
LastSequenceNumber: eseqno,
|
LastSequenceNumber: eseqno,
|
||||||
|
Jitter: t.jitter.Jitter(),
|
||||||
|
LastSenderReport: lastSR,
|
||||||
|
Delay: delay,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
return conn.pc.WriteRTCP([]rtcp.Packet{
|
return conn.pc.WriteRTCP([]rtcp.Packet{
|
||||||
&rtcp.ReceiverReport{
|
&rtcp.ReceiverReport{
|
||||||
SSRC: ssrc,
|
SSRC: 1,
|
||||||
Reports: reports,
|
Reports: reports,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -609,6 +620,9 @@ func rtcpDownListener(g *group, conn *downConnection, track *downTrack, s *webrt
|
||||||
&track.loss,
|
&track.loss,
|
||||||
uint32(r.FractionLost),
|
uint32(r.FractionLost),
|
||||||
)
|
)
|
||||||
|
atomic.StoreUint32(
|
||||||
|
&track.jitter,
|
||||||
|
r.Jitter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *rtcp.TransportLayerNack:
|
case *rtcp.TransportLayerNack:
|
||||||
|
|
4
group.go
4
group.go
|
@ -17,6 +17,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sfu/estimator"
|
"sfu/estimator"
|
||||||
|
"sfu/jitter"
|
||||||
"sfu/mono"
|
"sfu/mono"
|
||||||
"sfu/packetcache"
|
"sfu/packetcache"
|
||||||
|
|
||||||
|
@ -27,9 +28,11 @@ type upTrack struct {
|
||||||
track *webrtc.Track
|
track *webrtc.Track
|
||||||
rate *estimator.Estimator
|
rate *estimator.Estimator
|
||||||
cache *packetcache.Cache
|
cache *packetcache.Cache
|
||||||
|
jitter *jitter.Estimator
|
||||||
maxBitrate uint64
|
maxBitrate uint64
|
||||||
lastPLI uint64
|
lastPLI uint64
|
||||||
lastSenderReport uint32
|
lastSenderReport uint32
|
||||||
|
lastSenderReportTime uint32
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
local []*downTrack
|
local []*downTrack
|
||||||
|
@ -96,6 +99,7 @@ type downTrack struct {
|
||||||
maxBitrate *timeStampedBitrate
|
maxBitrate *timeStampedBitrate
|
||||||
rate *estimator.Estimator
|
rate *estimator.Estimator
|
||||||
loss uint32
|
loss uint32
|
||||||
|
jitter uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type downConnection struct {
|
type downConnection struct {
|
||||||
|
|
49
jitter/jitter.go
Normal file
49
jitter/jitter.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package jitter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
"sfu/mono"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Estimator struct {
|
||||||
|
hz uint32
|
||||||
|
timestamp uint32
|
||||||
|
time uint32
|
||||||
|
|
||||||
|
jitter uint32 // atomic
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(hz uint32) *Estimator {
|
||||||
|
return &Estimator{hz: hz}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Estimator) accumulate(timestamp, now uint32) {
|
||||||
|
if e.time == 0 {
|
||||||
|
e.timestamp = timestamp
|
||||||
|
e.time = now
|
||||||
|
}
|
||||||
|
|
||||||
|
d := uint32((e.time - now) - (e.timestamp - timestamp))
|
||||||
|
if d & 0x80000000 != 0 {
|
||||||
|
d = uint32(-int32(d))
|
||||||
|
}
|
||||||
|
oldjitter := atomic.LoadUint32(&e.jitter)
|
||||||
|
jitter := (oldjitter * 15 + d) / 16
|
||||||
|
atomic.StoreUint32(&e.jitter, jitter)
|
||||||
|
|
||||||
|
e.timestamp = timestamp
|
||||||
|
e.time = now
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Estimator) Accumulate(timestamp uint32) {
|
||||||
|
e.accumulate(timestamp, uint32(mono.Now(e.hz)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Estimator) Jitter() uint32 {
|
||||||
|
return atomic.LoadUint32(&e.jitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Estimator) HZ() uint32 {
|
||||||
|
return e.hz
|
||||||
|
}
|
37
jitter/jitter_test.go
Normal file
37
jitter/jitter_test.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package jitter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJitter(t *testing.T) {
|
||||||
|
e := New(48000)
|
||||||
|
e.accumulate(0, 0)
|
||||||
|
e.accumulate(1000, 1000)
|
||||||
|
e.accumulate(2000, 2000)
|
||||||
|
e.accumulate(3000, 3000)
|
||||||
|
|
||||||
|
if e.Jitter() != 0 {
|
||||||
|
t.Errorf("Expected 0, got %v", e.Jitter())
|
||||||
|
}
|
||||||
|
|
||||||
|
e = New(48000)
|
||||||
|
e.accumulate(0, 0)
|
||||||
|
e.accumulate(1000, 1000)
|
||||||
|
e.accumulate(2000, 2200)
|
||||||
|
e.accumulate(3000, 3000)
|
||||||
|
|
||||||
|
if e.Jitter() != 23 {
|
||||||
|
t.Errorf("Expected 23, got %v", e.Jitter())
|
||||||
|
}
|
||||||
|
|
||||||
|
e = New(48000)
|
||||||
|
e.accumulate(0, 0)
|
||||||
|
e.accumulate(1000, 1000)
|
||||||
|
e.accumulate(2000, 1800)
|
||||||
|
e.accumulate(3000, 3000)
|
||||||
|
|
||||||
|
if e.Jitter() != 23 {
|
||||||
|
t.Errorf("Expected 23, got %v", e.Jitter())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue