Skip to content

Commit 4dd2457

Browse files
committed
Include jitter and delay in receiver reports.
1 parent 7961d72 commit 4dd2457

File tree

4 files changed

+114
-10
lines changed

4 files changed

+114
-10
lines changed

client.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"time"
1919

2020
"sfu/estimator"
21+
"sfu/jitter"
2122
"sfu/mono"
2223
"sfu/packetcache"
2324

@@ -294,6 +295,7 @@ func addUpConn(c *client, id string) (*upConnection, error) {
294295
track: remote,
295296
cache: packetcache.New(96),
296297
rate: estimator.New(time.Second),
298+
jitter: jitter.New(remote.Codec().ClockRate),
297299
maxBitrate: ^uint64(0),
298300
}
299301
u.tracks = append(u.tracks, track)
@@ -323,7 +325,7 @@ func upLoop(conn *upConnection, track *upTrack) {
323325
var localTime uint64
324326
for {
325327
now := mono.Microseconds()
326-
if now < localTime || now > localTime + 500000 {
328+
if now < localTime || now > localTime+500000 {
327329
local = track.getLocal()
328330
localTime = now
329331
}
@@ -343,6 +345,8 @@ func upLoop(conn *upConnection, track *upTrack) {
343345
continue
344346
}
345347

348+
track.jitter.Accumulate(packet.Timestamp)
349+
346350
first := track.cache.Store(packet.SequenceNumber, buf[:bytes])
347351
if packet.SequenceNumber-first > 24 {
348352
first, bitmap := track.cache.BitmapGet()
@@ -379,6 +383,8 @@ func rtcpUpListener(conn *upConnection, track *upTrack, r *webrtc.RTPReceiver) {
379383
case *rtcp.SenderReport:
380384
atomic.StoreUint32(&track.lastSenderReport,
381385
uint32(p.NTPTime>>16))
386+
atomic.StoreUint32(&track.lastSenderReportTime,
387+
uint32(mono.Now(0x10000)))
382388
case *rtcp.SourceDescription:
383389
}
384390
}
@@ -392,7 +398,7 @@ func sendRR(c *client, conn *upConnection) error {
392398
return nil
393399
}
394400

395-
ssrc := conn.tracks[0].track.SSRC()
401+
now := uint32(mono.Now(0x10000))
396402

397403
reports := make([]rtcp.ReceptionReport, 0, len(conn.tracks))
398404
for _, t := range conn.tracks {
@@ -403,19 +409,24 @@ func sendRR(c *client, conn *upConnection) error {
403409
if lost >= expected {
404410
lost = expected - 1
405411
}
412+
lastSR := atomic.LoadUint32(&t.lastSenderReport)
413+
delay := now - atomic.LoadUint32(&t.lastSenderReportTime)
414+
406415
reports = append(reports, rtcp.ReceptionReport{
407416
SSRC: t.track.SSRC(),
408-
LastSenderReport: atomic.LoadUint32(&t.lastSenderReport),
409417
FractionLost: uint8((lost * 256) / expected),
410418
TotalLost: totalLost,
411419
LastSequenceNumber: eseqno,
420+
Jitter: t.jitter.Jitter(),
421+
LastSenderReport: lastSR,
422+
Delay: delay,
412423
})
413424
}
414425
c.mu.Unlock()
415426

416427
return conn.pc.WriteRTCP([]rtcp.Packet{
417428
&rtcp.ReceiverReport{
418-
SSRC: ssrc,
429+
SSRC: 1,
419430
Reports: reports,
420431
},
421432
})
@@ -609,6 +620,9 @@ func rtcpDownListener(g *group, conn *downConnection, track *downTrack, s *webrt
609620
&track.loss,
610621
uint32(r.FractionLost),
611622
)
623+
atomic.StoreUint32(
624+
&track.jitter,
625+
r.Jitter)
612626
}
613627
}
614628
case *rtcp.TransportLayerNack:

group.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,22 @@ import (
1717
"time"
1818

1919
"sfu/estimator"
20+
"sfu/jitter"
2021
"sfu/mono"
2122
"sfu/packetcache"
2223

2324
"github.com/pion/webrtc/v2"
2425
)
2526

2627
type upTrack struct {
27-
track *webrtc.Track
28-
rate *estimator.Estimator
29-
cache *packetcache.Cache
30-
maxBitrate uint64
31-
lastPLI uint64
32-
lastSenderReport uint32
28+
track *webrtc.Track
29+
rate *estimator.Estimator
30+
cache *packetcache.Cache
31+
jitter *jitter.Estimator
32+
maxBitrate uint64
33+
lastPLI uint64
34+
lastSenderReport uint32
35+
lastSenderReportTime uint32
3336

3437
mu sync.Mutex
3538
local []*downTrack
@@ -96,6 +99,7 @@ type downTrack struct {
9699
maxBitrate *timeStampedBitrate
97100
rate *estimator.Estimator
98101
loss uint32
102+
jitter uint32
99103
}
100104

101105
type downConnection struct {

jitter/jitter.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package jitter
2+
3+
import (
4+
"sync/atomic"
5+
6+
"sfu/mono"
7+
)
8+
9+
type Estimator struct {
10+
hz uint32
11+
timestamp uint32
12+
time uint32
13+
14+
jitter uint32 // atomic
15+
}
16+
17+
func New(hz uint32) *Estimator {
18+
return &Estimator{hz: hz}
19+
}
20+
21+
func (e *Estimator) accumulate(timestamp, now uint32) {
22+
if e.time == 0 {
23+
e.timestamp = timestamp
24+
e.time = now
25+
}
26+
27+
d := uint32((e.time - now) - (e.timestamp - timestamp))
28+
if d & 0x80000000 != 0 {
29+
d = uint32(-int32(d))
30+
}
31+
oldjitter := atomic.LoadUint32(&e.jitter)
32+
jitter := (oldjitter * 15 + d) / 16
33+
atomic.StoreUint32(&e.jitter, jitter)
34+
35+
e.timestamp = timestamp
36+
e.time = now
37+
}
38+
39+
func (e *Estimator) Accumulate(timestamp uint32) {
40+
e.accumulate(timestamp, uint32(mono.Now(e.hz)))
41+
}
42+
43+
func (e *Estimator) Jitter() uint32 {
44+
return atomic.LoadUint32(&e.jitter)
45+
}
46+
47+
func (e *Estimator) HZ() uint32 {
48+
return e.hz
49+
}

jitter/jitter_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package jitter
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestJitter(t *testing.T) {
8+
e := New(48000)
9+
e.accumulate(0, 0)
10+
e.accumulate(1000, 1000)
11+
e.accumulate(2000, 2000)
12+
e.accumulate(3000, 3000)
13+
14+
if e.Jitter() != 0 {
15+
t.Errorf("Expected 0, got %v", e.Jitter())
16+
}
17+
18+
e = New(48000)
19+
e.accumulate(0, 0)
20+
e.accumulate(1000, 1000)
21+
e.accumulate(2000, 2200)
22+
e.accumulate(3000, 3000)
23+
24+
if e.Jitter() != 23 {
25+
t.Errorf("Expected 23, got %v", e.Jitter())
26+
}
27+
28+
e = New(48000)
29+
e.accumulate(0, 0)
30+
e.accumulate(1000, 1000)
31+
e.accumulate(2000, 1800)
32+
e.accumulate(3000, 3000)
33+
34+
if e.Jitter() != 23 {
35+
t.Errorf("Expected 23, got %v", e.Jitter())
36+
}
37+
}

0 commit comments

Comments
 (0)