webrtc: use rtpReceiver and rtpSender to count packets (#5193)

This commit is contained in:
Alessandro Ros 2025-11-14 17:10:50 +01:00 committed by GitHub
parent d02fb4ed8e
commit 2d02ca0df7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 45 additions and 57 deletions

8
go.mod
View file

@ -12,7 +12,7 @@ require (
github.com/asticode/go-astits v1.14.0 github.com/asticode/go-astits v1.14.0
github.com/bluenviron/gohlslib/v2 v2.2.3 github.com/bluenviron/gohlslib/v2 v2.2.3
github.com/bluenviron/gortmplib v0.1.1 github.com/bluenviron/gortmplib v0.1.1
github.com/bluenviron/gortsplib/v5 v5.1.2-0.20251026101219-59474a8fa3ab github.com/bluenviron/gortsplib/v5 v5.1.2-0.20251112170709-0e56f305d197
github.com/bluenviron/mediacommon/v2 v2.5.1 github.com/bluenviron/mediacommon/v2 v2.5.1
github.com/datarhei/gosrt v0.9.0 github.com/datarhei/gosrt v0.9.0
github.com/fsnotify/fsnotify v1.9.0 github.com/fsnotify/fsnotify v1.9.0
@ -36,7 +36,7 @@ require (
github.com/pion/transport/v3 v3.1.1 github.com/pion/transport/v3 v3.1.1
github.com/pion/webrtc/v4 v4.1.6 github.com/pion/webrtc/v4 v4.1.6
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
golang.org/x/crypto v0.43.0 golang.org/x/crypto v0.44.0
golang.org/x/sys v0.38.0 golang.org/x/sys v0.38.0
golang.org/x/term v0.37.0 golang.org/x/term v0.37.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
@ -96,9 +96,9 @@ require (
go.uber.org/mock v0.5.0 // indirect go.uber.org/mock v0.5.0 // indirect
golang.org/x/arch v0.20.0 // indirect golang.org/x/arch v0.20.0 // indirect
golang.org/x/mod v0.29.0 // indirect golang.org/x/mod v0.29.0 // indirect
golang.org/x/net v0.46.0 // indirect golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect golang.org/x/sync v0.18.0 // indirect
golang.org/x/text v0.30.0 // indirect golang.org/x/text v0.31.0 // indirect
golang.org/x/time v0.9.0 // indirect golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.38.0 // indirect golang.org/x/tools v0.38.0 // indirect
google.golang.org/protobuf v1.36.9 // indirect google.golang.org/protobuf v1.36.9 // indirect

16
go.sum
View file

@ -37,8 +37,8 @@ github.com/bluenviron/gohlslib/v2 v2.2.3 h1:1R/Jnh1kNR9UB09KAX6xjS2GcdKFRLuPd9wM
github.com/bluenviron/gohlslib/v2 v2.2.3/go.mod h1:z4Viks+Mdgcl7OcOVJ1fgSmuUwCCJBxYJPLN49n7Vnw= github.com/bluenviron/gohlslib/v2 v2.2.3/go.mod h1:z4Viks+Mdgcl7OcOVJ1fgSmuUwCCJBxYJPLN49n7Vnw=
github.com/bluenviron/gortmplib v0.1.1 h1:pmR6qfPcJJmE17lWQ/bpuBFZtgGnMrN8KdFj1Gl/ZoQ= github.com/bluenviron/gortmplib v0.1.1 h1:pmR6qfPcJJmE17lWQ/bpuBFZtgGnMrN8KdFj1Gl/ZoQ=
github.com/bluenviron/gortmplib v0.1.1/go.mod h1:XWy2YzbTP1XEEZ8232OG7I1MSwubsbDRKDNhXGgS2kg= github.com/bluenviron/gortmplib v0.1.1/go.mod h1:XWy2YzbTP1XEEZ8232OG7I1MSwubsbDRKDNhXGgS2kg=
github.com/bluenviron/gortsplib/v5 v5.1.2-0.20251026101219-59474a8fa3ab h1:9QH6j4y2FMo299Rz/hX5jrhI+THhWgZ/oSiEmwSPavk= github.com/bluenviron/gortsplib/v5 v5.1.2-0.20251112170709-0e56f305d197 h1:NvBCxleaHdQwxZLpck4JwsOFYupbtg9+QnWnvRD2CYc=
github.com/bluenviron/gortsplib/v5 v5.1.2-0.20251026101219-59474a8fa3ab/go.mod h1:+4E4JNF7dpDu8LgssZu9fB3Ndh6FNbvGYMKOKR/wvvI= github.com/bluenviron/gortsplib/v5 v5.1.2-0.20251112170709-0e56f305d197/go.mod h1:IPHhCqTQvmKZ9t101dfnsf8xvVHM2oGGmxxEH8KMof4=
github.com/bluenviron/mediacommon/v2 v2.5.1 h1:qB2fb5c0xyl5OB2gfSfulpEJn7Cdm3vI2n8wjiLMxKI= github.com/bluenviron/mediacommon/v2 v2.5.1 h1:qB2fb5c0xyl5OB2gfSfulpEJn7Cdm3vI2n8wjiLMxKI=
github.com/bluenviron/mediacommon/v2 v2.5.1/go.mod h1:zy1fODPuS/kBd93ftgJS1Jhvjq7LFWfAo32KP7By9AE= github.com/bluenviron/mediacommon/v2 v2.5.1/go.mod h1:zy1fODPuS/kBd93ftgJS1Jhvjq7LFWfAo32KP7By9AE=
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
@ -239,16 +239,16 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -270,8 +270,8 @@ golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View file

@ -1,7 +1,6 @@
package webrtc package webrtc
import ( import (
"sync/atomic"
"time" "time"
"github.com/bluenviron/gortsplib/v5/pkg/rtpreceiver" "github.com/bluenviron/gortsplib/v5/pkg/rtpreceiver"
@ -243,8 +242,6 @@ type IncomingTrack struct {
receiver *webrtc.RTPReceiver receiver *webrtc.RTPReceiver
writeRTCP func([]rtcp.Packet) error writeRTCP func([]rtcp.Packet) error
log logger.Writer log logger.Writer
rtpPacketsReceived *uint64
rtpPacketsLost *uint64
packetsLost *counterdumper.CounterDumper packetsLost *counterdumper.CounterDumper
rtpReceiver *rtpreceiver.Receiver rtpReceiver *rtpreceiver.Receiver
@ -347,19 +344,13 @@ func (t *IncomingTrack) start() {
return return
} }
packets, lost, err2 := t.rtpReceiver.ProcessPacket(pkt, time.Now(), true) packets, lost := t.rtpReceiver.ProcessPacket2(pkt, time.Now(), true)
if err2 != nil {
t.log.Log(logger.Warn, err2.Error())
continue
}
if lost != 0 { if lost != 0 {
atomic.AddUint64(t.rtpPacketsLost, lost)
t.packetsLost.Add(lost) t.packetsLost.Add(lost)
// do not return // do not return
} }
atomic.AddUint64(t.rtpPacketsReceived, uint64(len(packets)))
for _, pkt := range packets { for _, pkt := range packets {
// sometimes Chrome sends empty RTP packets. ignore them. // sometimes Chrome sends empty RTP packets. ignore them.
if len(pkt.Payload) == 0 { if len(pkt.Payload) == 0 {

View file

@ -2,7 +2,6 @@ package webrtc
import ( import (
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/bluenviron/gortsplib/v5/pkg/rtpsender" "github.com/bluenviron/gortsplib/v5/pkg/rtpsender"
@ -18,7 +17,6 @@ type OutgoingTrack struct {
track *webrtc.TrackLocalStaticRTP track *webrtc.TrackLocalStaticRTP
ssrc uint32 ssrc uint32
rtcpSender *rtpsender.Sender rtcpSender *rtpsender.Sender
rtpPacketsSent *uint64
} }
func (t *OutgoingTrack) isVideo() bool { func (t *OutgoingTrack) isVideo() bool {
@ -60,8 +58,6 @@ func (t *OutgoingTrack) setup(p *PeerConnection) error {
} }
t.rtcpSender.Initialize() t.rtcpSender.Initialize()
t.rtpPacketsSent = p.rtpPacketsSent
// incoming RTCP packets must always be read to make interceptors work // incoming RTCP packets must always be read to make interceptors work
go func() { go func() {
buf := make([]byte, 1500) buf := make([]byte, 1500)
@ -99,7 +95,5 @@ func (t *OutgoingTrack) WriteRTPWithNTP(pkt *rtp.Packet, ntp time.Time) error {
t.rtcpSender.ProcessPacket(pkt, ntp, true) t.rtcpSender.ProcessPacket(pkt, ntp, true)
atomic.AddUint64(t.rtpPacketsSent, 1)
return t.track.WriteRTP(pkt) return t.track.WriteRTP(pkt)
} }

View file

@ -152,9 +152,6 @@ type PeerConnection struct {
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
incomingTracks []*IncomingTrack incomingTracks []*IncomingTrack
startedReading *int64 startedReading *int64
rtpPacketsReceived *uint64
rtpPacketsSent *uint64
rtpPacketsLost *uint64
statsInterceptor *statsInterceptor statsInterceptor *statsInterceptor
newLocalCandidate chan *webrtc.ICECandidateInit newLocalCandidate chan *webrtc.ICECandidateInit
@ -303,9 +300,6 @@ func (co *PeerConnection) Start() error {
co.ctx, co.ctxCancel = context.WithCancel(context.Background()) co.ctx, co.ctxCancel = context.WithCancel(context.Background())
co.startedReading = new(int64) co.startedReading = new(int64)
co.rtpPacketsReceived = new(uint64)
co.rtpPacketsSent = new(uint64)
co.rtpPacketsLost = new(uint64)
co.newLocalCandidate = make(chan *webrtc.ICECandidateInit) co.newLocalCandidate = make(chan *webrtc.ICECandidateInit)
co.connected = make(chan struct{}) co.connected = make(chan struct{})
@ -711,8 +705,6 @@ func (co *PeerConnection) GatherIncomingTracks() error {
receiver: pair.receiver, receiver: pair.receiver,
writeRTCP: co.wr.WriteRTCP, writeRTCP: co.wr.WriteRTCP,
log: co.Log, log: co.Log,
rtpPacketsReceived: co.rtpPacketsReceived,
rtpPacketsLost: co.rtpPacketsLost,
} }
t.initialize() t.initialize()
co.incomingTracks = append(co.incomingTracks, t) co.incomingTracks = append(co.incomingTracks, t)
@ -810,16 +802,27 @@ func (co *PeerConnection) Stats() *Stats {
v := float64(0) v := float64(0)
n := float64(0) n := float64(0)
packetsReceived := uint64(0)
packetsSent := uint64(0)
packetsLost := uint64(0)
if atomic.LoadInt64(co.startedReading) == 1 { if atomic.LoadInt64(co.startedReading) == 1 {
for _, tr := range co.incomingTracks { for _, tr := range co.incomingTracks {
if recvStats := tr.rtpReceiver.Stats(); recvStats != nil { if recvStats := tr.rtpReceiver.Stats(); recvStats != nil {
v += recvStats.Jitter v += recvStats.Jitter
n++ n++
packetsReceived += recvStats.TotalReceived
packetsLost += recvStats.TotalLost
} }
} }
} }
for _, tr := range co.OutgoingTracks {
if sentStats := tr.rtcpSender.Stats(); sentStats != nil {
packetsSent += sentStats.TotalSent
}
}
var rtpPacketsJitter float64 var rtpPacketsJitter float64
if n != 0 { if n != 0 {
rtpPacketsJitter = v / n rtpPacketsJitter = v / n
@ -830,9 +833,9 @@ func (co *PeerConnection) Stats() *Stats {
return &Stats{ return &Stats{
BytesReceived: bytesReceived, BytesReceived: bytesReceived,
BytesSent: bytesSent, BytesSent: bytesSent,
RTPPacketsReceived: atomic.LoadUint64(co.rtpPacketsReceived), RTPPacketsReceived: packetsReceived,
RTPPacketsSent: atomic.LoadUint64(co.rtpPacketsSent), RTPPacketsSent: packetsSent,
RTPPacketsLost: atomic.LoadUint64(co.rtpPacketsLost), RTPPacketsLost: packetsLost,
RTPPacketsJitter: rtpPacketsJitter, RTPPacketsJitter: rtpPacketsJitter,
RTCPPacketsReceived: atomic.LoadUint64(co.statsInterceptor.rtcpPacketsReceived), RTCPPacketsReceived: atomic.LoadUint64(co.statsInterceptor.rtcpPacketsReceived),
RTCPPacketsSent: atomic.LoadUint64(co.statsInterceptor.rtcpPacketsSent), RTCPPacketsSent: atomic.LoadUint64(co.statsInterceptor.rtcpPacketsSent),