mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
Compute down track RTT.
This commit is contained in:
parent
49bccda5ee
commit
19a65318c9
6 changed files with 55 additions and 19 deletions
3
conn.go
3
conn.go
|
@ -281,6 +281,9 @@ type rtpDownTrack struct {
|
||||||
maxREMBBitrate *bitrate
|
maxREMBBitrate *bitrate
|
||||||
rate *estimator.Estimator
|
rate *estimator.Estimator
|
||||||
stats *receiverStats
|
stats *receiverStats
|
||||||
|
srTime uint64
|
||||||
|
srNTPTime uint64
|
||||||
|
rtt uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (down *rtpDownTrack) WriteRTP(packet *rtp.Packet) error {
|
func (down *rtpDownTrack) WriteRTP(packet *rtp.Packet) error {
|
||||||
|
|
4
group.go
4
group.go
|
@ -518,6 +518,7 @@ type trackStats struct {
|
||||||
bitrate uint64
|
bitrate uint64
|
||||||
maxBitrate uint64
|
maxBitrate uint64
|
||||||
loss uint8
|
loss uint8
|
||||||
|
rtt time.Duration
|
||||||
jitter time.Duration
|
jitter time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,6 +590,8 @@ func getClientStats(c *webClient) clientStats {
|
||||||
conns := connStats{id: down.id}
|
conns := connStats{id: down.id}
|
||||||
for _, t := range down.tracks {
|
for _, t := range down.tracks {
|
||||||
jiffies := rtptime.Jiffies()
|
jiffies := rtptime.Jiffies()
|
||||||
|
rtt := rtptime.ToDuration(atomic.LoadUint64(&t.rtt),
|
||||||
|
rtptime.JiffiesPerSec)
|
||||||
loss, jitter := t.stats.Get(jiffies)
|
loss, jitter := t.stats.Get(jiffies)
|
||||||
j := time.Duration(jitter) * time.Second /
|
j := time.Duration(jitter) * time.Second /
|
||||||
time.Duration(t.track.Codec().ClockRate)
|
time.Duration(t.track.Codec().ClockRate)
|
||||||
|
@ -596,6 +599,7 @@ func getClientStats(c *webClient) clientStats {
|
||||||
bitrate: uint64(t.rate.Estimate()) * 8,
|
bitrate: uint64(t.rate.Estimate()) * 8,
|
||||||
maxBitrate: t.GetMaxBitrate(jiffies),
|
maxBitrate: t.GetMaxBitrate(jiffies),
|
||||||
loss: uint8(uint32(loss) * 100 / 256),
|
loss: uint8(uint32(loss) * 100 / 256),
|
||||||
|
rtt: rtt,
|
||||||
jitter: j,
|
jitter: j,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ func FromDuration(d time.Duration, hz uint32) uint64 {
|
||||||
return uint64(d) * uint64(hz) / uint64(time.Second)
|
return uint64(d) * uint64(hz) / uint64(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toDuration(tm uint64, hz uint32) time.Duration {
|
func ToDuration(tm uint64, hz uint32) time.Duration {
|
||||||
return time.Duration(tm * uint64(time.Second) / uint64(hz))
|
return time.Duration(tm * uint64(time.Second) / uint64(hz))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,10 @@ func Jiffies() uint64 {
|
||||||
return Now(JiffiesPerSec)
|
return Now(JiffiesPerSec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TimeToJiffies(tm time.Time) uint64 {
|
||||||
|
return FromDuration(tm.Sub(epoch), JiffiesPerSec)
|
||||||
|
}
|
||||||
|
|
||||||
var ntpEpoch = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
|
var ntpEpoch = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
func NTPToTime(ntp uint64) time.Time {
|
func NTPToTime(ntp uint64) time.Time {
|
||||||
|
|
|
@ -11,7 +11,7 @@ func TestDuration(t *testing.T) {
|
||||||
t.Errorf("Expected 48000, got %v", a)
|
t.Errorf("Expected 48000, got %v", a)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := toDuration(48000, 48000)
|
b := ToDuration(48000, 48000)
|
||||||
if b != time.Second {
|
if b != time.Second {
|
||||||
t.Errorf("Expected %v, got %v", time.Second, b)
|
t.Errorf("Expected %v, got %v", time.Second, b)
|
||||||
}
|
}
|
||||||
|
|
48
webclient.go
48
webclient.go
|
@ -20,8 +20,8 @@ import (
|
||||||
|
|
||||||
"sfu/estimator"
|
"sfu/estimator"
|
||||||
"sfu/jitter"
|
"sfu/jitter"
|
||||||
"sfu/rtptime"
|
|
||||||
"sfu/packetcache"
|
"sfu/packetcache"
|
||||||
|
"sfu/rtptime"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/pion/rtcp"
|
"github.com/pion/rtcp"
|
||||||
|
@ -633,6 +633,7 @@ func sendSR(conn *rtpDownConnection) error {
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
nowNTP := rtptime.TimeToNTP(now)
|
nowNTP := rtptime.TimeToNTP(now)
|
||||||
|
jiffies := rtptime.TimeToJiffies(now)
|
||||||
|
|
||||||
for _, t := range conn.tracks {
|
for _, t := range conn.tracks {
|
||||||
clockrate := t.track.Codec().ClockRate
|
clockrate := t.track.Codec().ClockRate
|
||||||
|
@ -661,6 +662,8 @@ func sendSR(conn *rtpDownConnection) error {
|
||||||
PacketCount: p,
|
PacketCount: p,
|
||||||
OctetCount: b,
|
OctetCount: b,
|
||||||
})
|
})
|
||||||
|
atomic.StoreUint64(&t.srTime, jiffies)
|
||||||
|
atomic.StoreUint64(&t.srNTPTime, nowNTP)
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn.pc.WriteRTCP(packets)
|
return conn.pc.WriteRTCP(packets)
|
||||||
|
@ -876,6 +879,7 @@ func rtcpDownListener(conn *rtpDownConnection, track *rtpDownTrack, s *webrtc.RT
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
jiffies := rtptime.Jiffies()
|
||||||
|
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
switch p := p.(type) {
|
switch p := p.(type) {
|
||||||
|
@ -918,25 +922,21 @@ func rtcpDownListener(conn *rtpDownConnection, track *rtpDownTrack, s *webrtc.RT
|
||||||
log.Printf("sendFIR: %v", err)
|
log.Printf("sendFIR: %v", err)
|
||||||
}
|
}
|
||||||
case *rtcp.ReceiverEstimatedMaximumBitrate:
|
case *rtcp.ReceiverEstimatedMaximumBitrate:
|
||||||
track.maxREMBBitrate.Set(
|
track.maxREMBBitrate.Set(p.Bitrate, jiffies)
|
||||||
p.Bitrate, rtptime.Jiffies(),
|
|
||||||
)
|
|
||||||
case *rtcp.ReceiverReport:
|
case *rtcp.ReceiverReport:
|
||||||
for _, r := range p.Reports {
|
for _, r := range p.Reports {
|
||||||
if r.SSRC == track.track.SSRC() {
|
if r.SSRC == track.track.SSRC() {
|
||||||
handleReport(track, r)
|
handleReport(track, r, jiffies)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *rtcp.SenderReport:
|
case *rtcp.SenderReport:
|
||||||
for _, r := range p.Reports {
|
for _, r := range p.Reports {
|
||||||
if r.SSRC == track.track.SSRC() {
|
if r.SSRC == track.track.SSRC() {
|
||||||
handleReport(track, r)
|
handleReport(track, r, jiffies)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *rtcp.TransportLayerNack:
|
case *rtcp.TransportLayerNack:
|
||||||
maxBitrate := track.GetMaxBitrate(
|
maxBitrate := track.GetMaxBitrate(jiffies)
|
||||||
rtptime.Jiffies(),
|
|
||||||
)
|
|
||||||
bitrate := track.rate.Estimate()
|
bitrate := track.rate.Estimate()
|
||||||
if uint64(bitrate)*7/8 < maxBitrate {
|
if uint64(bitrate)*7/8 < maxBitrate {
|
||||||
sendRecovery(p, track)
|
sendRecovery(p, track)
|
||||||
|
@ -946,10 +946,32 @@ func rtcpDownListener(conn *rtpDownConnection, track *rtpDownTrack, s *webrtc.RT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleReport(track *rtpDownTrack, report rtcp.ReceptionReport) {
|
func handleReport(track *rtpDownTrack, report rtcp.ReceptionReport, jiffies uint64) {
|
||||||
jiffies := rtptime.Jiffies()
|
|
||||||
track.stats.Set(report.FractionLost, report.Jitter, jiffies)
|
track.stats.Set(report.FractionLost, report.Jitter, jiffies)
|
||||||
track.updateRate(report.FractionLost, jiffies)
|
track.updateRate(report.FractionLost, jiffies)
|
||||||
|
|
||||||
|
if report.LastSenderReport != 0 {
|
||||||
|
jiffies := rtptime.Jiffies()
|
||||||
|
srTime := atomic.LoadUint64(&track.srTime)
|
||||||
|
if jiffies < srTime || jiffies-srTime > 8*rtptime.JiffiesPerSec {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srNTPTime := atomic.LoadUint64(&track.srNTPTime)
|
||||||
|
if report.LastSenderReport == uint32(srNTPTime>>16) {
|
||||||
|
delay := uint64(report.Delay) *
|
||||||
|
(rtptime.JiffiesPerSec / 0x10000)
|
||||||
|
if delay > jiffies-srTime {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rtt := (jiffies - srTime) - delay
|
||||||
|
oldrtt := atomic.LoadUint64(&track.rtt)
|
||||||
|
newrtt := rtt
|
||||||
|
if oldrtt > 0 {
|
||||||
|
newrtt = (3*oldrtt + rtt) / 4
|
||||||
|
}
|
||||||
|
atomic.StoreUint64(&track.rtt, newrtt)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func trackKinds(down *rtpDownConnection) (audio bool, video bool) {
|
func trackKinds(down *rtpDownConnection) (audio bool, video bool) {
|
||||||
|
@ -1013,7 +1035,7 @@ func (up *upConnection) sendPLI(track *upTrack) error {
|
||||||
}
|
}
|
||||||
last := atomic.LoadUint64(&track.lastPLI)
|
last := atomic.LoadUint64(&track.lastPLI)
|
||||||
now := rtptime.Jiffies()
|
now := rtptime.Jiffies()
|
||||||
if now >= last && now-last < rtptime.JiffiesPerSec / 5 {
|
if now >= last && now-last < rtptime.JiffiesPerSec/5 {
|
||||||
return ErrRateLimited
|
return ErrRateLimited
|
||||||
}
|
}
|
||||||
atomic.StoreUint64(&track.lastPLI, now)
|
atomic.StoreUint64(&track.lastPLI, now)
|
||||||
|
@ -1041,7 +1063,7 @@ func (up *upConnection) sendFIR(track *upTrack, increment bool) error {
|
||||||
}
|
}
|
||||||
last := atomic.LoadUint64(&track.lastFIR)
|
last := atomic.LoadUint64(&track.lastFIR)
|
||||||
now := rtptime.Jiffies()
|
now := rtptime.Jiffies()
|
||||||
if now >= last && now-last < rtptime.JiffiesPerSec / 5 {
|
if now >= last && now-last < rtptime.JiffiesPerSec/5 {
|
||||||
return ErrRateLimited
|
return ErrRateLimited
|
||||||
}
|
}
|
||||||
atomic.StoreUint64(&track.lastFIR, now)
|
atomic.StoreUint64(&track.lastFIR, now)
|
||||||
|
|
11
webserver.go
11
webserver.go
|
@ -154,11 +154,14 @@ func statsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "<td>%d%%</td>",
|
fmt.Fprintf(w, "<td>%d%%</td>",
|
||||||
t.loss,
|
t.loss,
|
||||||
)
|
)
|
||||||
if t.jitter > 0 {
|
fmt.Fprintf(w, "<td>")
|
||||||
fmt.Fprintf(w, "<td>%v</td>", t.jitter)
|
if t.rtt > 0 {
|
||||||
} else {
|
fmt.Fprintf(w, "%v", t.rtt)
|
||||||
fmt.Fprintf(w, "<td></td>")
|
|
||||||
}
|
}
|
||||||
|
if t.jitter > 0 {
|
||||||
|
fmt.Fprintf(w, "±%v", t.jitter)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "</td>")
|
||||||
fmt.Fprintf(w, "</tr>")
|
fmt.Fprintf(w, "</tr>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue