refactor statistics (#1020)

This commit is contained in:
Alessandro Ros
2026-03-16 20:51:58 +01:00
committed by GitHub
parent d8b8536dd0
commit e55d889e89
26 changed files with 585 additions and 417 deletions
+4 -4
View File
@@ -22,8 +22,8 @@ Features:
* Read selected media streams
* Pause or seek without disconnecting from the server
* Write to ONVIF back channels
* Get PTS (presentation timestamp) of incoming packets
* Get NTP (absolute timestamp) of incoming packets
* Get PTS (presentation timestamp) of inbound packets
* Get NTP (absolute timestamp) of inbound packets
* Write media streams to a server ("record")
* Write streams with the UDP or TCP transport protocol
* Switch transport protocol automatically
@@ -35,8 +35,8 @@ Features:
* Validate client credentials
* Read media streams from clients ("record")
* Read streams with the UDP or TCP transport protocol
* Get PTS (presentation timestamp) of incoming packets
* Get NTP (absolute timestamp) of incoming packets
* Get PTS (presentation timestamp) of inbound packets
* Get NTP (absolute timestamp) of inbound packets
* Serve media streams to clients ("play")
* Write streams with the UDP, UDP-multicast or TCP transport protocol
* Compute and provide SSRC, RTP-Info to clients
+8 -91
View File
@@ -481,10 +481,10 @@ type Client struct {
// This can be increased to reduce packet losses.
// It defaults to the operating system default value.
UDPReadBufferSize int
// Size of the queue of outgoing packets.
// Size of the queue of outbound packets.
// It defaults to 256.
WriteQueueSize int
// maximum size of outgoing RTP / RTCP packets.
// maximum size of outbound RTP / RTCP packets.
// This must be less than the IPv4/UDP MTU (1472 bytes).
// It defaults to 1472.
MaxPacketSize int
@@ -495,7 +495,7 @@ type Client struct {
DisableRTCPSenderReports bool
// explicitly request back channels to the server.
RequestBackChannels bool
// Range of ports used as source port in outgoing UDP packets.
// Range of ports used as source port in outbound UDP packets.
// It defaults to [10000, 65535].
UDPSourcePortRange [2]uint16
@@ -2424,7 +2424,7 @@ func (c *Client) WritePacketRTCP(medi *description.Media, pkt rtcp.Packet) error
return cm.writePacketRTCP(pkt)
}
// PacketPTS returns the PTS (presentation timestamp) of an incoming RTP packet.
// PacketPTS returns the PTS (presentation timestamp) of an inbound RTP packet.
// It is computed by decoding the packet timestamp and sychronizing it with other tracks.
func (c *Client) PacketPTS(medi *description.Media, pkt *rtp.Packet) (int64, bool) {
cm := c.setuppedMedias[medi]
@@ -2432,7 +2432,7 @@ func (c *Client) PacketPTS(medi *description.Media, pkt *rtp.Packet) (int64, boo
return c.timeDecoder.Decode(ct.format, pkt)
}
// PacketNTP returns the NTP (absolute timestamp) of an incoming RTP packet.
// PacketNTP returns the NTP (absolute timestamp) of an inbound RTP packet.
// The NTP is computed from RTCP sender reports.
func (c *Client) PacketNTP(medi *description.Media, pkt *rtp.Packet) (time.Time, bool) {
cm := c.setuppedMedias[medi]
@@ -2468,94 +2468,11 @@ func (c *Client) Stats() *ClientStats {
return &ClientStats{
Conn: ConnStats{
InboundBytes: atomic.LoadUint64(c.bytesReceived),
OutboundBytes: atomic.LoadUint64(c.bytesSent),
BytesReceived: atomic.LoadUint64(c.bytesReceived),
BytesSent: atomic.LoadUint64(c.bytesSent),
},
Session: SessionStats{ //nolint:dupl
BytesReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesReceived
}
return v
}(),
BytesSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesSent
}
return v
}(),
RTPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsReceived
}
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsSent
}
}
return v
}(),
RTPPacketsLost: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsLost
}
}
return v
}(),
RTPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTPPacketsInError
}
return v
}(),
RTPPacketsJitter: func() float64 {
v := float64(0)
n := float64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsJitter
n++
}
}
if n != 0 {
return v / n
}
return 0
}(),
RTCPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsReceived
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsSent
}
return v
}(),
RTCPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsInError
}
return v
}(),
Medias: mediaStats,
},
Session: sessionStatsFromMedias(mediaStats),
}
}
+68 -7
View File
@@ -91,24 +91,66 @@ func (cf *clientFormat) stats() SessionStatsFormat { //nolint:dupl
}
return SessionStatsFormat{
RTPPacketsReceived: func() uint64 {
InboundRTPPackets: func() uint64 {
if recvStats != nil {
return recvStats.TotalReceived
return recvStats.Received
}
return 0
}(),
RTPPacketsSent: func() uint64 {
InboundRTPPacketsLost: func() uint64 {
if recvStats != nil {
return recvStats.Lost
}
return 0
}(),
InboundRTPPacketsJitter: func() float64 {
if recvStats != nil {
return recvStats.Jitter
}
return 0
}(),
InboundRTPPacketsLastSequenceNumber: func() uint16 {
if recvStats != nil {
return recvStats.LastSequenceNumber
}
return 0
}(),
InboundRTPPacketsLastRTP: func() uint32 {
if recvStats != nil {
return recvStats.LastRTP
}
return 0
}(),
InboundRTPPacketsLastNTP: func() time.Time {
if recvStats != nil {
return recvStats.LastNTP
}
return time.Time{}
}(),
OutboundRTPPackets: func() uint64 {
if sentStats != nil {
return sentStats.TotalSent
return sentStats.Sent
}
return 0
}(),
RTPPacketsLost: func() uint64 {
if recvStats != nil {
return recvStats.TotalLost
OutboundRTPPacketsLastSequenceNumber: func() uint16 {
if sentStats != nil {
return sentStats.LastSequenceNumber
}
return 0
}(),
OutboundRTPPacketsLastRTP: func() uint32 {
if sentStats != nil {
return sentStats.LastRTP
}
return 0
}(),
OutboundRTPPacketsLastNTP: func() time.Time {
if sentStats != nil {
return sentStats.LastNTP
}
return time.Time{}
}(),
LocalSSRC: cf.localSSRC,
RemoteSSRC: func() uint32 {
if v, ok := cf.remoteSSRC(); ok {
@@ -116,6 +158,25 @@ func (cf *clientFormat) stats() SessionStatsFormat { //nolint:dupl
}
return 0
}(),
// deprecated
RTPPacketsReceived: func() uint64 {
if recvStats != nil {
return recvStats.Received
}
return 0
}(),
RTPPacketsSent: func() uint64 {
if sentStats != nil {
return sentStats.Sent
}
return 0
}(),
RTPPacketsLost: func() uint64 {
if recvStats != nil {
return recvStats.Lost
}
return 0
}(),
RTPPacketsLastSequenceNumber: func() uint16 {
if recvStats != nil {
return recvStats.LastSequenceNumber
+14 -7
View File
@@ -205,14 +205,14 @@ func (cm *clientMedia) stop() {
}
}
func (cm *clientMedia) stats() SessionStatsMedia {
func (cm *clientMedia) stats() SessionStatsMedia { //nolint:dupl
return SessionStatsMedia{
BytesReceived: atomic.LoadUint64(cm.bytesReceived),
BytesSent: atomic.LoadUint64(cm.bytesSent),
RTPPacketsInError: atomic.LoadUint64(cm.rtpPacketsInError),
RTCPPacketsReceived: atomic.LoadUint64(cm.rtcpPacketsReceived),
RTCPPacketsSent: atomic.LoadUint64(cm.rtcpPacketsSent),
RTCPPacketsInError: atomic.LoadUint64(cm.rtcpPacketsInError),
InboundBytes: atomic.LoadUint64(cm.bytesReceived),
InboundRTPPacketsInError: atomic.LoadUint64(cm.rtpPacketsInError),
InboundRTCPPackets: atomic.LoadUint64(cm.rtcpPacketsReceived),
InboundRTCPPacketsInError: atomic.LoadUint64(cm.rtcpPacketsInError),
OutboundBytes: atomic.LoadUint64(cm.bytesSent),
OutboundRTCPPackets: atomic.LoadUint64(cm.rtcpPacketsSent),
Formats: func() map[format.Format]SessionStatsFormat {
ret := make(map[format.Format]SessionStatsFormat, len(cm.formats))
for _, fo := range cm.formats {
@@ -220,6 +220,13 @@ func (cm *clientMedia) stats() SessionStatsMedia {
}
return ret
}(),
// deprecated
BytesReceived: atomic.LoadUint64(cm.bytesReceived),
BytesSent: atomic.LoadUint64(cm.bytesSent),
RTPPacketsInError: atomic.LoadUint64(cm.rtpPacketsInError),
RTCPPacketsReceived: atomic.LoadUint64(cm.rtcpPacketsReceived),
RTCPPacketsSent: atomic.LoadUint64(cm.rtcpPacketsSent),
RTCPPacketsInError: atomic.LoadUint64(cm.rtcpPacketsInError),
}
}
+30 -41
View File
@@ -652,47 +652,36 @@ func TestClientPlay(t *testing.T) {
// test that stats are available after client is closed
s := c.Stats()
require.Equal(t, &ClientStats{
Conn: ConnStats{
BytesReceived: s.Conn.BytesReceived,
BytesSent: s.Conn.BytesSent,
},
Session: SessionStats{
BytesReceived: s.Session.BytesReceived,
BytesSent: s.Session.BytesSent,
RTPPacketsReceived: s.Session.RTPPacketsReceived,
RTCPPacketsReceived: s.Session.RTCPPacketsReceived,
RTCPPacketsSent: s.Session.RTCPPacketsSent,
Medias: map[*description.Media]SessionStatsMedia{
sd.Medias[0]: { //nolint:dupl
BytesReceived: s.Session.Medias[sd.Medias[0]].BytesReceived,
BytesSent: s.Session.Medias[sd.Medias[0]].BytesSent,
RTCPPacketsReceived: s.Session.Medias[sd.Medias[0]].RTCPPacketsReceived,
RTCPPacketsSent: s.Session.Medias[sd.Medias[0]].RTCPPacketsSent,
Formats: map[format.Format]SessionStatsFormat{
sd.Medias[0].Formats[0]: {
RTPPacketsReceived: s.Session.Medias[sd.Medias[0]].Formats[sd.Medias[0].Formats[0]].RTPPacketsReceived,
LocalSSRC: s.Session.Medias[sd.Medias[0]].Formats[sd.Medias[0].Formats[0]].LocalSSRC,
RemoteSSRC: s.Session.Medias[sd.Medias[0]].Formats[sd.Medias[0].Formats[0]].RemoteSSRC,
},
},
},
sd.Medias[1]: { //nolint:dupl
BytesReceived: s.Session.Medias[sd.Medias[1]].BytesReceived,
BytesSent: s.Session.Medias[sd.Medias[1]].BytesSent,
RTCPPacketsReceived: s.Session.Medias[sd.Medias[1]].RTCPPacketsReceived,
RTCPPacketsSent: s.Session.Medias[sd.Medias[1]].RTCPPacketsSent,
Formats: map[format.Format]SessionStatsFormat{
sd.Medias[1].Formats[0]: {
RTPPacketsReceived: s.Session.Medias[sd.Medias[1]].Formats[sd.Medias[1].Formats[0]].RTPPacketsReceived,
LocalSSRC: s.Session.Medias[sd.Medias[1]].Formats[sd.Medias[1].Formats[0]].LocalSSRC,
RemoteSSRC: s.Session.Medias[sd.Medias[1]].Formats[sd.Medias[1].Formats[0]].RemoteSSRC,
},
},
},
},
},
}, s)
require.Equal(t, s.Conn.InboundBytes, s.Conn.BytesReceived)
require.Equal(t, s.Conn.OutboundBytes, s.Conn.BytesSent)
require.Equal(t, s.Session.InboundBytes, s.Session.BytesReceived)
require.Equal(t, s.Session.OutboundBytes, s.Session.BytesSent)
require.Equal(t, s.Session.InboundRTPPackets, s.Session.RTPPacketsReceived)
require.Equal(t, s.Session.InboundRTCPPackets, s.Session.RTCPPacketsReceived)
require.Equal(t, s.Session.OutboundRTCPPackets, s.Session.RTCPPacketsSent)
require.Len(t, s.Session.Medias, 2)
media0 := s.Session.Medias[sd.Medias[0]]
require.Equal(t, media0.InboundBytes, media0.BytesReceived)
require.Equal(t, media0.OutboundBytes, media0.BytesSent)
require.Equal(t, media0.InboundRTCPPackets, media0.RTCPPacketsReceived)
require.Equal(t, media0.OutboundRTCPPackets, media0.RTCPPacketsSent)
format0 := media0.Formats[sd.Medias[0].Formats[0]]
require.Equal(t, format0.InboundRTPPackets, format0.RTPPacketsReceived)
require.Equal(t, format0.InboundRTPPacketsLost, format0.RTPPacketsLost)
require.Equal(t, format0.InboundRTPPacketsJitter, format0.RTPPacketsJitter)
require.Equal(t, format0.InboundRTPPacketsLastSequenceNumber, format0.RTPPacketsLastSequenceNumber)
media1 := s.Session.Medias[sd.Medias[1]]
require.Equal(t, media1.InboundBytes, media1.BytesReceived)
require.Equal(t, media1.OutboundBytes, media1.BytesSent)
require.Equal(t, media1.InboundRTCPPackets, media1.RTCPPacketsReceived)
require.Equal(t, media1.OutboundRTCPPackets, media1.RTCPPacketsSent)
format1 := media1.Formats[sd.Medias[1].Formats[0]]
require.Equal(t, format1.InboundRTPPackets, format1.RTPPacketsReceived)
require.Equal(t, format1.InboundRTPPacketsLost, format1.RTPPacketsLost)
require.Equal(t, format1.InboundRTPPacketsJitter, format1.RTPPacketsJitter)
require.Equal(t, format1.InboundRTPPacketsLastSequenceNumber, format1.RTPPacketsLastSequenceNumber)
require.Greater(t, s.Session.BytesSent, uint64(19))
require.Less(t, s.Session.BytesSent, uint64(70))
+23 -31
View File
@@ -451,37 +451,29 @@ func TestClientRecord(t *testing.T) {
// test that stats are available after client is closed
s := c.Stats()
require.Equal(t, &ClientStats{
Conn: ConnStats{
BytesReceived: s.Conn.BytesReceived,
BytesSent: s.Conn.BytesSent,
},
Session: SessionStats{
BytesReceived: s.Session.BytesReceived,
BytesSent: s.Session.BytesSent,
RTPPacketsSent: s.Session.RTPPacketsSent,
RTPPacketsReceived: s.Session.RTPPacketsReceived,
RTCPPacketsReceived: s.Session.RTCPPacketsReceived,
RTCPPacketsSent: s.Session.RTCPPacketsSent,
Medias: map[*description.Media]SessionStatsMedia{
medias[0]: {
BytesReceived: s.Session.Medias[medias[0]].BytesReceived,
BytesSent: s.Session.Medias[medias[0]].BytesSent,
RTCPPacketsReceived: s.Session.Medias[medias[0]].RTCPPacketsReceived,
RTCPPacketsSent: s.Session.Medias[medias[0]].RTCPPacketsSent,
Formats: map[format.Format]SessionStatsFormat{
medias[0].Formats[0]: {
RTPPacketsSent: s.Session.Medias[medias[0]].Formats[medias[0].Formats[0]].RTPPacketsSent,
RTPPacketsReceived: s.Session.Medias[medias[0]].Formats[medias[0].Formats[0]].RTPPacketsReceived,
LocalSSRC: s.Session.Medias[medias[0]].Formats[medias[0].Formats[0]].LocalSSRC,
RemoteSSRC: s.Session.Medias[medias[0]].Formats[medias[0].Formats[0]].RemoteSSRC,
RTPPacketsLastNTP: s.Session.Medias[medias[0]].Formats[medias[0].Formats[0]].RTPPacketsLastNTP,
},
},
},
},
},
}, s)
require.Equal(t, s.Conn.InboundBytes, s.Conn.BytesReceived)
require.Equal(t, s.Conn.OutboundBytes, s.Conn.BytesSent)
require.Equal(t, s.Session.InboundBytes, s.Session.BytesReceived)
require.Equal(t, s.Session.OutboundBytes, s.Session.BytesSent)
require.Equal(t, s.Session.InboundRTPPackets, s.Session.RTPPacketsReceived)
require.Equal(t, s.Session.OutboundRTPPackets, s.Session.RTPPacketsSent)
require.Equal(t, s.Session.InboundRTCPPackets, s.Session.RTCPPacketsReceived)
require.Equal(t, s.Session.OutboundRTCPPackets, s.Session.RTCPPacketsSent)
require.Len(t, s.Session.Medias, 1)
mediaStats := s.Session.Medias[medias[0]]
require.Equal(t, mediaStats.InboundBytes, mediaStats.BytesReceived)
require.Equal(t, mediaStats.OutboundBytes, mediaStats.BytesSent)
require.Equal(t, mediaStats.InboundRTCPPackets, mediaStats.RTCPPacketsReceived)
require.Equal(t, mediaStats.OutboundRTCPPackets, mediaStats.RTCPPacketsSent)
formatStats := mediaStats.Formats[medias[0].Formats[0]]
require.Equal(t, formatStats.InboundRTPPackets, formatStats.RTPPacketsReceived)
require.Equal(t, formatStats.OutboundRTPPackets, formatStats.RTPPacketsSent)
require.Equal(t, formatStats.InboundRTPPacketsLost, formatStats.RTPPacketsLost)
require.Equal(t, formatStats.InboundRTPPacketsJitter, formatStats.RTPPacketsJitter)
require.Equal(t, formatStats.InboundRTPPacketsLastSequenceNumber, formatStats.RTPPacketsLastSequenceNumber)
require.Equal(t, formatStats.OutboundRTPPacketsLastNTP, formatStats.RTPPacketsLastNTP)
require.Greater(t, s.Session.BytesSent, uint64(15))
require.Less(t, s.Session.BytesSent, uint64(30))
+7 -2
View File
@@ -2,8 +2,13 @@ package gortsplib
// ConnStats are connection statistics.
type ConnStats struct {
// received bytes
// inbound bytes
InboundBytes uint64
// outbound bytes
OutboundBytes uint64
// Deprecated: use InboundBytes.
BytesReceived uint64
// sent bytes
// Deprecated: use OutboundBytes.
BytesSent uint64
}
+1 -1
View File
@@ -14,7 +14,7 @@ import (
// This example shows how to:
// 1. connect to a RTSP server.
// 2. read all media streams on a path.
// 3. Get PTS and NTP of incoming RTP packets.
// 3. Get PTS and NTP of inbound RTP packets.
func main() {
// parse URL
+1 -1
View File
@@ -102,7 +102,7 @@ func (c *client) read() error {
rc.OnPacketRTPAny(func(medi *description.Media, _ format.Format, pkt *rtp.Packet) {
log.Printf("received RTP packet from the client, routing to readers")
// route incoming packets to the server stream
// route inbound packets to the server stream
err2 := stream.WritePacketRTP(medi, pkt)
if err2 != nil {
log.Printf("ERR: %v", err2)
+1 -1
View File
@@ -73,7 +73,7 @@ func (c *client) read() error {
// called when a RTP packet arrives
rc.OnPacketRTPAny(func(medi *description.Media, _ format.Format, pkt *rtp.Packet) {
// route incoming packets to the server stream
// route inbound packets to the server stream
err2 := stream.WritePacketRTP(medi, pkt)
if err2 != nil {
log.Printf("ERR: %v", err2)
+1 -1
View File
@@ -83,7 +83,7 @@ func (sh *serverHandler) OnPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Re
return
}
log.Printf("incoming RTP packet with PTS=%v size=%v", pts, len(pkt.Payload))
log.Printf("inbound RTP packet with PTS=%v size=%v", pts, len(pkt.Payload))
})
return &base.Response{
+53 -40
View File
@@ -44,21 +44,21 @@ type Receiver struct {
mutex sync.RWMutex
// data from RTP packets
firstRTPPacketReceived bool
timeInitialized bool
buffer []*rtp.Packet
absPos uint16
negativeCount int
sequenceNumberCycles uint16
lastValidSeqNum uint16
remoteSSRC uint32
lastRTP uint32
lastSystem time.Time
totalLost uint64
totalLostSinceReport uint64
totalReceived uint64
totalReceivedAndLostSinceReport uint64
jitter float64
firstRTPPacketReceived bool
timeInitialized bool
buffer []*rtp.Packet
absPos uint16
negativeCount int
sequenceNumberCycles uint16
lastValidSeqNum uint16
remoteSSRC uint32
lastRTP uint32
lastSystem time.Time
lost uint64
lostSinceReport uint64
received uint64
receivedAndLostSinceReport uint64
jitter float64
// data from RTCP sender reports
firstSenderReportReceived bool
@@ -133,10 +133,10 @@ func (rr *Receiver) report() rtcp.Packet {
system := rr.TimeNow()
var fractionLost uint8
if rr.totalReceivedAndLostSinceReport != 0 {
if rr.receivedAndLostSinceReport != 0 {
// equivalent to taking the integer part after multiplying the
// loss fraction by 256
fractionLost = uint8((min(rr.totalLostSinceReport, 0xFFFFFF) * 256) / rr.totalReceivedAndLostSinceReport)
fractionLost = uint8((min(rr.lostSinceReport, 0xFFFFFF) * 256) / rr.receivedAndLostSinceReport)
}
report := &rtcp.ReceiverReport{
@@ -146,7 +146,7 @@ func (rr *Receiver) report() rtcp.Packet {
SSRC: rr.remoteSSRC,
LastSequenceNumber: uint32(rr.sequenceNumberCycles)<<16 | uint32(rr.lastValidSeqNum),
FractionLost: fractionLost,
TotalLost: uint32(min(rr.totalLost, 0xFFFFFF)), // allow up to 24 bits
TotalLost: uint32(min(rr.lost, 0xFFFFFF)), // allow up to 24 bits
Jitter: uint32(rr.jitter),
},
},
@@ -162,13 +162,13 @@ func (rr *Receiver) report() rtcp.Packet {
report.Reports[0].Delay = uint32(system.Sub(rr.lastSenderReportTimeSystem).Seconds() * 65536)
}
rr.totalLostSinceReport = 0
rr.totalReceivedAndLostSinceReport = 0
rr.lostSinceReport = 0
rr.receivedAndLostSinceReport = 0
return report
}
// ProcessPacket processes an incoming RTP packet.
// ProcessPacket processes an inbound RTP packet.
// It returns reordered packets and number of lost packets.
//
// Deprecated: replaced by ProcessPacket2.
@@ -181,7 +181,7 @@ func (rr *Receiver) ProcessPacket(
return pkts, lost, nil
}
// ProcessPacket2 processes an incoming RTP packet.
// ProcessPacket2 processes an inbound RTP packet.
// It returns reordered packets and number of lost packets.
func (rr *Receiver) ProcessPacket2(
pkt *rtp.Packet,
@@ -194,8 +194,8 @@ func (rr *Receiver) ProcessPacket2(
// first packet
if !rr.firstRTPPacketReceived {
rr.firstRTPPacketReceived = true
rr.totalReceived = 1
rr.totalReceivedAndLostSinceReport = 1
rr.received = 1
rr.receivedAndLostSinceReport = 1
rr.lastValidSeqNum = pkt.SequenceNumber
rr.remoteSSRC = pkt.SSRC
@@ -218,10 +218,10 @@ func (rr *Receiver) ProcessPacket2(
lost = uint64(pkt.SequenceNumber - rr.lastValidSeqNum - 1)
}
rr.totalLost += lost
rr.totalLostSinceReport += lost
rr.totalReceived += uint64(len(pkts))
rr.totalReceivedAndLostSinceReport += uint64(len(pkts)) + lost
rr.lost += lost
rr.lostSinceReport += lost
rr.received += uint64(len(pkts))
rr.receivedAndLostSinceReport += uint64(len(pkts)) + lost
for _, pkt := range pkts {
// overflow
@@ -348,7 +348,7 @@ func (rr *Receiver) reorder(pkt *rtp.Packet) ([]*rtp.Packet, uint64) {
return ret, 0
}
// ProcessSenderReport processes an incoming RTCP sender report.
// ProcessSenderReport processes an inbound RTCP sender report.
func (rr *Receiver) ProcessSenderReport(sr *rtcp.SenderReport, system time.Time) {
rr.mutex.Lock()
defer rr.mutex.Unlock()
@@ -380,15 +380,25 @@ func (rr *Receiver) PacketNTP(ts uint32) (time.Time, bool) {
// Stats are statistics.
type Stats struct {
// number of inbound RTP packets correctly received and processed.
Received uint64
// number of lost inbound RTP packets.
Lost uint64
// Jitter of inbound RTP packets.
Jitter float64
// Last sequence number of inbound RTP packets.
LastSequenceNumber uint16
// Last RTP time of inbound RTP packets.
LastRTP uint32
// Last NTP time of inbound RTP packets.
LastNTP time.Time
// Deprecated: use Received.
TotalReceived uint64
// Deprecated: use Lost.
TotalLost uint64
// Deprecated: will be removed in next version.
RemoteSSRC uint32
LastSequenceNumber uint16
LastRTP uint32
LastNTP time.Time
Jitter float64
TotalReceived uint64
TotalLost uint64
}
// Stats returns statistics.
@@ -403,12 +413,15 @@ func (rr *Receiver) Stats() *Stats {
ntp, _ := rr.packetNTPUnsafe(rr.lastRTP)
return &Stats{
RemoteSSRC: rr.remoteSSRC,
Received: rr.received,
Lost: rr.lost,
Jitter: rr.jitter,
LastSequenceNumber: rr.lastValidSeqNum,
LastRTP: rr.lastRTP,
LastNTP: ntp,
Jitter: rr.jitter,
TotalReceived: rr.totalReceived,
TotalLost: rr.totalLost,
// deprecated
TotalReceived: rr.received,
TotalLost: rr.lost,
RemoteSSRC: rr.remoteSSRC,
}
}
+24 -11
View File
@@ -114,10 +114,11 @@ func TestStandard(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 1,
LastRTP: 0xafb45733,
LastSequenceNumber: 945,
TotalReceived: 1,
RemoteSSRC: 0xba9da416,
}, stats)
srPkt := rtcp.SenderReport{
@@ -136,11 +137,12 @@ func TestStandard(t *testing.T) {
stats = rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 1,
LastRTP: 0xafb45733,
LastSequenceNumber: 945,
LastNTP: time.Date(2008, 5, 20, 22, 15, 20, 0, time.UTC).Local(),
TotalReceived: 1,
RemoteSSRC: 0xba9da416,
}, stats)
rtpPkt = rtp.Packet{
@@ -188,11 +190,12 @@ func TestStandard(t *testing.T) {
stats = rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 3,
LastRTP: 2947921603,
LastSequenceNumber: 947,
LastNTP: time.Date(2008, 5, 20, 22, 15, 21, 0, time.UTC).Local(),
TotalReceived: 3,
RemoteSSRC: 0xba9da416,
}, stats)
})
}
@@ -276,10 +279,11 @@ func TestZeroClockRate(t *testing.T) {
stats = rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 1,
LastRTP: 0xafb45733,
LastSequenceNumber: 945,
TotalReceived: 1,
RemoteSSRC: 0xba9da416,
}, stats)
srPkt := rtcp.SenderReport{
@@ -294,10 +298,11 @@ func TestZeroClockRate(t *testing.T) {
stats = rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 1,
LastRTP: 0xafb45733,
LastSequenceNumber: 945,
TotalReceived: 1,
RemoteSSRC: 0xba9da416,
}, stats)
rtpPkt = rtp.Packet{
@@ -338,10 +343,11 @@ func TestZeroClockRate(t *testing.T) {
stats = rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 3,
LastRTP: 2947921603,
LastSequenceNumber: 947,
TotalReceived: 3,
RemoteSSRC: 0xba9da416,
}, stats)
}
@@ -585,12 +591,14 @@ func TestReliablePacketsLost(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 2,
Lost: 1,
LastRTP: 0xafb45733,
LastSequenceNumber: 290,
LastNTP: time.Date(2020, 11, 21, 17, 44, 36, 869277776, time.UTC).Local(),
TotalReceived: 2,
TotalLost: 1,
RemoteSSRC: 0xba9da416,
}, stats)
}
@@ -672,12 +680,14 @@ func TestReliableOverflowAndPacketsLost(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0xba9da416,
Received: 2,
Lost: 2,
LastRTP: 0xafb45733,
LastSequenceNumber: 2,
LastNTP: time.Date(2020, 11, 21, 17, 44, 36, 869277776, time.UTC).Local(),
TotalReceived: 2,
TotalLost: 2,
RemoteSSRC: stats.RemoteSSRC,
}, stats)
}
@@ -854,7 +864,7 @@ func TestUnrealiableReorder(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0,
Received: 8,
LastRTP: 0,
LastSequenceNumber: 1,
TotalReceived: 8,
@@ -946,7 +956,8 @@ func TestUnrealiableBufferFull(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0,
Received: 32,
Lost: 34,
LastRTP: 0,
LastSequenceNumber: 1629,
TotalReceived: 32,
@@ -1017,7 +1028,7 @@ func TestUnrealiableReset(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
RemoteSSRC: 0,
Received: 2,
LastRTP: 0,
LastSequenceNumber: 40064,
TotalReceived: 2,
@@ -1078,6 +1089,8 @@ func TestUnrealiableCustomBufferSize(t *testing.T) {
stats := rr.Stats()
require.Equal(t, &Stats{
Received: 2,
Lost: 130,
LastSequenceNumber: 181,
TotalReceived: 2,
TotalLost: 130,
+16 -7
View File
@@ -29,7 +29,7 @@ type Sender struct {
lastSystem time.Time
localSSRC uint32
lastSequenceNumber uint16
totalSent uint64
sent uint64
octetCount uint32
terminate chan struct{}
@@ -90,7 +90,7 @@ func (rs *Sender) report() rtcp.Packet {
SSRC: rs.localSSRC,
NTPTime: ntp.Encode(ntpTime),
RTPTime: rtpTime,
PacketCount: uint32(rs.totalSent),
PacketCount: uint32(rs.sent),
OctetCount: rs.octetCount,
}
}
@@ -110,16 +110,23 @@ func (rs *Sender) ProcessPacket(pkt *rtp.Packet, ntp time.Time, ptsEqualsDTS boo
rs.lastSequenceNumber = pkt.SequenceNumber
rs.totalSent++
rs.sent++
rs.octetCount += uint32(len(pkt.Payload))
}
// Stats are statistics.
type Stats struct {
// number of outbound RTP packets.
Sent uint64
// last sequence number of outbound RTP packets.
LastSequenceNumber uint16
LastRTP uint32
LastNTP time.Time
TotalSent uint64
// last RTP time of outbound RTP packets.
LastRTP uint32
// last NTP time of outbound RTP packets.
LastNTP time.Time
// Deprecated: use Sent.
TotalSent uint64
}
// Stats returns statistics.
@@ -132,9 +139,11 @@ func (rs *Sender) Stats() *Stats {
}
return &Stats{
Sent: rs.sent,
LastSequenceNumber: rs.lastSequenceNumber,
LastRTP: rs.lastRTP,
LastNTP: rs.lastNTP,
TotalSent: rs.totalSent,
// deprecated
TotalSent: rs.sent,
}
}
+2
View File
@@ -101,6 +101,7 @@ func TestSender(t *testing.T) {
stats = rs.Stats()
require.Equal(t, &Stats{
Sent: 3,
LastSequenceNumber: 948,
LastRTP: 1287987768,
LastNTP: time.Date(2008, time.May, 20, 22, 15, 21, 0, time.UTC),
@@ -161,6 +162,7 @@ func TestSenderZeroClockRate(t *testing.T) {
stats = rs.Stats()
require.Equal(t, &Stats{
Sent: 1,
LastSequenceNumber: 946,
LastRTP: 1287987768,
LastNTP: time.Date(2008, time.May, 20, 22, 15, 20, 0, time.UTC),
+2 -2
View File
@@ -102,10 +102,10 @@ type Server struct {
// This can be increased to reduce packet losses.
// It defaults to the operating system default value.
UDPReadBufferSize int
// Size of the queue of outgoing packets.
// Size of the queue of outbound packets.
// It defaults to 256.
WriteQueueSize int
// maximum size of outgoing RTP / RTCP packets.
// maximum size of outbound RTP / RTCP packets.
// This must be less than the IPv4/UDP MTU (1472 bytes).
// It defaults to 1472.
MaxPacketSize int
+2
View File
@@ -202,6 +202,8 @@ func (sc *ServerConn) Transport() *ConnTransport {
// Stats returns connection statistics.
func (sc *ServerConn) Stats() *ConnStats {
return &ConnStats{
InboundBytes: sc.bc.BytesReceived(),
OutboundBytes: sc.bc.BytesSent(),
BytesReceived: sc.bc.BytesReceived(),
BytesSent: sc.bc.BytesSent(),
}
+12 -5
View File
@@ -2693,21 +2693,28 @@ func TestServerPlayStreamStats(t *testing.T) {
st := stream.Stats()
require.Equal(t, &ServerStreamStats{
BytesSent: 32,
RTPPacketsSent: 2,
OutboundBytes: 32,
OutboundRTPPackets: 2,
OutboundRTCPPackets: 0,
Medias: map[*description.Media]ServerStreamStatsMedia{
stream.Desc.Medias[0]: {
BytesSent: 32,
RTCPPacketsSent: 0,
OutboundBytes: 32,
OutboundRTCPPackets: 0,
Formats: map[format.Format]ServerStreamStatsFormat{
stream.Desc.Medias[0].Formats[0]: {
RTPPacketsSent: 2,
OutboundRTPPackets: 2,
LocalSSRC: st.Medias[stream.Desc.Medias[0]].
Formats[stream.Desc.Medias[0].Formats[0]].LocalSSRC,
RTPPacketsSent: 2,
},
},
BytesSent: 32,
RTCPPacketsSent: 0,
},
},
BytesSent: 32,
RTPPacketsSent: 2,
RTCPPacketsSent: 0,
}, st)
}
+4 -88
View File
@@ -457,92 +457,8 @@ func (ss *ServerSession) Stats() *SessionStats {
return ret
}()
return &SessionStats{ //nolint:dupl
BytesReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesReceived
}
return v
}(),
BytesSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesSent
}
return v
}(),
RTPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsReceived
}
}
return v
}(),
RTPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsSent
}
}
return v
}(),
RTPPacketsLost: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsLost
}
}
return v
}(),
RTPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTPPacketsInError
}
return v
}(),
RTPPacketsJitter: func() float64 {
v := float64(0)
n := float64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsJitter
n++
}
}
if n != 0 {
return v / n
}
return 0
}(),
RTCPPacketsReceived: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsReceived
}
return v
}(),
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsSent
}
return v
}(),
RTCPPacketsInError: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsInError
}
return v
}(),
Medias: mediaStats,
}
stats := sessionStatsFromMedias(mediaStats)
return &stats
}
func (ss *ServerSession) onStreamWriteError(err error) {
@@ -1636,7 +1552,7 @@ func (ss *ServerSession) WritePacketRTCP(medi *description.Media, pkt rtcp.Packe
return sm.writePacketRTCP(pkt)
}
// PacketPTS returns the PTS (presentation timestamp) of an incoming RTP packet.
// PacketPTS returns the PTS (presentation timestamp) of an inbound RTP packet.
// It is computed by decoding the packet timestamp and sychronizing it with other tracks.
func (ss *ServerSession) PacketPTS(medi *description.Media, pkt *rtp.Packet) (int64, bool) {
sm := ss.setuppedMedias[medi]
@@ -1644,7 +1560,7 @@ func (ss *ServerSession) PacketPTS(medi *description.Media, pkt *rtp.Packet) (in
return ss.timeDecoder.Decode(sf.format, pkt)
}
// PacketNTP returns the NTP (absolute timestamp) of an incoming RTP packet.
// PacketNTP returns the NTP (absolute timestamp) of an inbound RTP packet.
// The NTP is computed from RTCP sender reports.
func (ss *ServerSession) PacketNTP(medi *description.Media, pkt *rtp.Packet) (time.Time, bool) {
sm := ss.setuppedMedias[medi]
+68 -7
View File
@@ -95,24 +95,66 @@ func (ssf *serverSessionFormat) stats() SessionStatsFormat { //nolint:dupl
}
return SessionStatsFormat{
RTPPacketsReceived: func() uint64 {
InboundRTPPackets: func() uint64 {
if recvStats != nil {
return recvStats.TotalReceived
return recvStats.Received
}
return 0
}(),
RTPPacketsSent: func() uint64 {
InboundRTPPacketsLost: func() uint64 {
if recvStats != nil {
return recvStats.Lost
}
return 0
}(),
InboundRTPPacketsJitter: func() float64 {
if recvStats != nil {
return recvStats.Jitter
}
return 0
}(),
InboundRTPPacketsLastSequenceNumber: func() uint16 {
if recvStats != nil {
return recvStats.LastSequenceNumber
}
return 0
}(),
InboundRTPPacketsLastRTP: func() uint32 {
if recvStats != nil {
return recvStats.LastRTP
}
return 0
}(),
InboundRTPPacketsLastNTP: func() time.Time {
if recvStats != nil {
return recvStats.LastNTP
}
return time.Time{}
}(),
OutboundRTPPackets: func() uint64 {
if sentStats != nil {
return sentStats.TotalSent
return sentStats.Sent
}
return 0
}(),
RTPPacketsLost: func() uint64 {
if recvStats != nil {
return recvStats.TotalLost
OutboundRTPPacketsLastSequenceNumber: func() uint16 {
if sentStats != nil {
return sentStats.LastSequenceNumber
}
return 0
}(),
OutboundRTPPacketsLastRTP: func() uint32 {
if sentStats != nil {
return sentStats.LastRTP
}
return 0
}(),
OutboundRTPPacketsLastNTP: func() time.Time {
if sentStats != nil {
return sentStats.LastNTP
}
return time.Time{}
}(),
LocalSSRC: ssf.localSSRC,
RemoteSSRC: func() uint32 {
if v, ok := ssf.remoteSSRC(); ok {
@@ -120,6 +162,25 @@ func (ssf *serverSessionFormat) stats() SessionStatsFormat { //nolint:dupl
}
return 0
}(),
// deprecated
RTPPacketsReceived: func() uint64 {
if recvStats != nil {
return recvStats.Received
}
return 0
}(),
RTPPacketsSent: func() uint64 {
if sentStats != nil {
return sentStats.Sent
}
return 0
}(),
RTPPacketsLost: func() uint64 {
if recvStats != nil {
return recvStats.Lost
}
return 0
}(),
RTPPacketsLastSequenceNumber: func() uint16 {
if recvStats != nil {
return recvStats.LastSequenceNumber
+14 -7
View File
@@ -143,14 +143,14 @@ func (ssm *serverSessionMedia) stop() {
}
}
func (ssm *serverSessionMedia) stats() SessionStatsMedia {
func (ssm *serverSessionMedia) stats() SessionStatsMedia { //nolint:dupl
return SessionStatsMedia{
BytesReceived: atomic.LoadUint64(ssm.bytesReceived),
BytesSent: atomic.LoadUint64(ssm.bytesSent),
RTPPacketsInError: atomic.LoadUint64(ssm.rtpPacketsInError),
RTCPPacketsReceived: atomic.LoadUint64(ssm.rtcpPacketsReceived),
RTCPPacketsSent: atomic.LoadUint64(ssm.rtcpPacketsSent),
RTCPPacketsInError: atomic.LoadUint64(ssm.rtcpPacketsInError),
InboundBytes: atomic.LoadUint64(ssm.bytesReceived),
InboundRTPPacketsInError: atomic.LoadUint64(ssm.rtpPacketsInError),
InboundRTCPPackets: atomic.LoadUint64(ssm.rtcpPacketsReceived),
InboundRTCPPacketsInError: atomic.LoadUint64(ssm.rtcpPacketsInError),
OutboundBytes: atomic.LoadUint64(ssm.bytesSent),
OutboundRTCPPackets: atomic.LoadUint64(ssm.rtcpPacketsSent),
Formats: func() map[format.Format]SessionStatsFormat {
ret := make(map[format.Format]SessionStatsFormat, len(ssm.formats))
for _, ssf := range ssm.formats {
@@ -158,6 +158,13 @@ func (ssm *serverSessionMedia) stats() SessionStatsMedia {
}
return ret
}(),
// deprecated
BytesReceived: atomic.LoadUint64(ssm.bytesReceived),
BytesSent: atomic.LoadUint64(ssm.bytesSent),
RTPPacketsInError: atomic.LoadUint64(ssm.rtpPacketsInError),
RTCPPacketsReceived: atomic.LoadUint64(ssm.rtcpPacketsReceived),
RTCPPacketsSent: atomic.LoadUint64(ssm.rtcpPacketsSent),
RTCPPacketsInError: atomic.LoadUint64(ssm.rtcpPacketsInError),
}
}
+28 -4
View File
@@ -149,10 +149,35 @@ func (st *ServerStream) Stats() *ServerStreamStats {
}()
return &ServerStreamStats{
OutboundBytes: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.OutboundBytes
}
return v
}(),
OutboundRTPPackets: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.OutboundRTPPackets
}
}
return v
}(),
OutboundRTCPPackets: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.OutboundRTCPPackets
}
return v
}(),
Medias: mediaStats,
// deprecated
BytesSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.BytesSent
v += ms.OutboundBytes
}
return v
}(),
@@ -160,7 +185,7 @@ func (st *ServerStream) Stats() *ServerStreamStats {
v := uint64(0)
for _, ms := range mediaStats {
for _, f := range ms.Formats {
v += f.RTPPacketsSent
v += f.OutboundRTPPackets
}
}
return v
@@ -168,11 +193,10 @@ func (st *ServerStream) Stats() *ServerStreamStats {
RTCPPacketsSent: func() uint64 {
v := uint64(0)
for _, ms := range mediaStats {
v += ms.RTCPPacketsSent
v += ms.OutboundRTCPPackets
}
return v
}(),
Medias: mediaStats,
}
}
+5 -2
View File
@@ -71,9 +71,12 @@ func (ssf *serverStreamFormat) stats() ServerStreamStatsFormat {
ssf.mutex.RLock()
defer ssf.mutex.RUnlock()
rtpPacketsSent := ssf.rtpPacketsSent
return ServerStreamStatsFormat{
RTPPacketsSent: ssf.rtpPacketsSent,
LocalSSRC: ssf.localSSRC,
OutboundRTPPackets: rtpPacketsSent,
LocalSSRC: ssf.localSSRC,
RTPPacketsSent: rtpPacketsSent,
}
}
+8 -2
View File
@@ -53,9 +53,12 @@ func (ssm *serverStreamMedia) rtpInfoEntry(now time.Time) *headers.RTPInfoEntry
}
func (ssm *serverStreamMedia) stats() ServerStreamStatsMedia {
bytesSent := atomic.LoadUint64(ssm.bytesSent)
rtcpPacketsSent := atomic.LoadUint64(ssm.rtcpPacketsSent)
return ServerStreamStatsMedia{
BytesSent: atomic.LoadUint64(ssm.bytesSent),
RTCPPacketsSent: atomic.LoadUint64(ssm.rtcpPacketsSent),
OutboundBytes: bytesSent,
OutboundRTCPPackets: rtcpPacketsSent,
Formats: func() map[format.Format]ServerStreamStatsFormat {
ret := make(map[format.Format]ServerStreamStatsFormat)
for _, ssf := range ssm.formats {
@@ -63,6 +66,9 @@ func (ssm *serverStreamMedia) stats() ServerStreamStatsMedia {
}
return ret
}(),
// deprecated
BytesSent: bytesSent,
RTCPPacketsSent: rtcpPacketsSent,
}
}
+27 -12
View File
@@ -7,32 +7,47 @@ import (
// ServerStreamStatsFormat are stream format statistics.
type ServerStreamStatsFormat struct {
// number of sent RTP packets
RTPPacketsSent uint64
// number of outbound RTP packets
OutboundRTPPackets uint64
// local SSRC
LocalSSRC uint32
// Deprecated: use OutboundRTPPackets.
RTPPacketsSent uint64
}
// ServerStreamStatsMedia are stream media statistics.
type ServerStreamStatsMedia struct {
// sent bytes
BytesSent uint64
// number of sent RTCP packets
RTCPPacketsSent uint64
// outbound bytes
OutboundBytes uint64
// number of outbound RTCP packets
OutboundRTCPPackets uint64
// format statistics
Formats map[format.Format]ServerStreamStatsFormat
// Deprecated: use OutboundBytes.
BytesSent uint64
// Deprecated: use OutboundRTCPPackets.
RTCPPacketsSent uint64
}
// ServerStreamStats are stream statistics.
type ServerStreamStats struct {
// sent bytes
BytesSent uint64
// number of sent RTP packets
RTPPacketsSent uint64
// number of sent RTCP packets
RTCPPacketsSent uint64
// outbound bytes
OutboundBytes uint64
// number of outbound RTP packets
OutboundRTPPackets uint64
// number of outbound RTCP packets
OutboundRTCPPackets uint64
// media statistics
Medias map[*description.Media]ServerStreamStatsMedia
// Deprecated: use OutboundBytes.
BytesSent uint64
// Deprecated: use OutboundRTPPackets.
RTPPacketsSent uint64
// Deprecated: use OutboundRTCPPackets.
RTCPPacketsSent uint64
}
+162 -43
View File
@@ -9,68 +9,187 @@ import (
// SessionStatsFormat are session format statistics.
type SessionStatsFormat struct {
// number of RTP packets correctly received and processed
RTPPacketsReceived uint64
// number of sent RTP packets
RTPPacketsSent uint64
// number of lost RTP packets
RTPPacketsLost uint64
// mean jitter of received RTP packets
RTPPacketsJitter float64
// number of inbound RTP packets correctly received and processed
InboundRTPPackets uint64
// number of lost inbound RTP packets
InboundRTPPacketsLost uint64
// mean jitter of inbound RTP packets
InboundRTPPacketsJitter float64
// last sequence number of inbound RTP packets
InboundRTPPacketsLastSequenceNumber uint16
// last RTP time of inbound RTP packets
InboundRTPPacketsLastRTP uint32
// last NTP time of inbound RTP packets
InboundRTPPacketsLastNTP time.Time
// number of outbound RTP packets
OutboundRTPPackets uint64
// last sequence number of outbound RTP packets
OutboundRTPPacketsLastSequenceNumber uint16
// last RTP time of outbound RTP packets
OutboundRTPPacketsLastRTP uint32
// last NTP time of outbound RTP packets
OutboundRTPPacketsLastNTP time.Time
// local SSRC
LocalSSRC uint32
// remote SSRC
RemoteSSRC uint32
// last sequence number of incoming/outgoing RTP packets
// Deprecated: use InboundRTPPacketsLastSequenceNumber or OutboundRTPPacketsLastSequenceNumber.
RTPPacketsLastSequenceNumber uint16
// last RTP time of incoming/outgoing RTP packets
// Deprecated: use InboundRTPPacketsLastRTP or OutboundRTPPacketsLastRTP.
RTPPacketsLastRTP uint32
// last NTP time of incoming/outgoing NTP packets
// Deprecated: use InboundRTPPacketsLastNTP or OutboundRTPPacketsLastNTP.
RTPPacketsLastNTP time.Time
// Deprecated: use InboundRTPPackets.
RTPPacketsReceived uint64
// Deprecated: use OutboundRTPPackets.
RTPPacketsSent uint64
// Deprecated: use InboundRTPPacketsLost.
RTPPacketsLost uint64
// Deprecated: use InboundRTPPacketsJitter.
RTPPacketsJitter float64
}
// SessionStatsMedia are session media statistics.
type SessionStatsMedia struct {
// received bytes
BytesReceived uint64
// sent bytes
BytesSent uint64
// number of RTP packets that could not be processed
RTPPacketsInError uint64
// number of RTCP packets correctly received and processed
RTCPPacketsReceived uint64
// number of sent RTCP packets
RTCPPacketsSent uint64
// number of RTCP packets that could not be processed
RTCPPacketsInError uint64
// inbound bytes
InboundBytes uint64
// number of inbound RTP packets that could not be processed
InboundRTPPacketsInError uint64
// number of inbound RTCP packets correctly received and processed
InboundRTCPPackets uint64
// number of inbound RTCP packets that could not be processed
InboundRTCPPacketsInError uint64
// outbound bytes
OutboundBytes uint64
// number of outbound RTCP packets
OutboundRTCPPackets uint64
// format statistics
Formats map[format.Format]SessionStatsFormat
// Deprecated: use InboundBytes.
BytesReceived uint64
// Deprecated: use OutboundBytes.
BytesSent uint64
// Deprecated: use InboundRTPPacketsInError.
RTPPacketsInError uint64
// Deprecated: use InboundRTCPPackets.
RTCPPacketsReceived uint64
// Deprecated: use OutboundRTCPPackets.
RTCPPacketsSent uint64
// Deprecated: use InboundRTCPPacketsInError.
RTCPPacketsInError uint64
}
// SessionStats are session statistics.
type SessionStats struct {
// received bytes
BytesReceived uint64
// sent bytes
BytesSent uint64
// number of RTP packets correctly received and processed
RTPPacketsReceived uint64
// number of sent RTP packets
RTPPacketsSent uint64
// number of lost RTP packets
RTPPacketsLost uint64
// number of RTP packets that could not be processed
RTPPacketsInError uint64
// mean jitter of received RTP packets
RTPPacketsJitter float64
// number of RTCP packets correctly received and processed
RTCPPacketsReceived uint64
// number of sent RTCP packets
RTCPPacketsSent uint64
// number of RTCP packets that could not be processed
RTCPPacketsInError uint64
// inbound bytes
InboundBytes uint64
// number of inbound RTP packets correctly received and processed
InboundRTPPackets uint64
// number of lost inbound RTP packets
InboundRTPPacketsLost uint64
// number of inbound RTP packets that could not be processed
InboundRTPPacketsInError uint64
// mean jitter of inbound RTP packets
InboundRTPPacketsJitter float64
// number of inbound RTCP packets correctly received and processed
InboundRTCPPackets uint64
// number of inbound RTCP packets that could not be processed
InboundRTCPPacketsInError uint64
// outbound bytes
OutboundBytes uint64
// number of outbound RTP packets
OutboundRTPPackets uint64
// number of outbound RTCP packets
OutboundRTCPPackets uint64
// media statistics
Medias map[*description.Media]SessionStatsMedia
// Deprecated: use InboundBytes.
BytesReceived uint64
// Deprecated: use OutboundBytes.
BytesSent uint64
// Deprecated: use InboundRTPPackets.
RTPPacketsReceived uint64
// Deprecated: use OutboundRTPPackets.
RTPPacketsSent uint64
// Deprecated: use InboundRTPPacketsLost.
RTPPacketsLost uint64
// Deprecated: use InboundRTPPacketsInError.
RTPPacketsInError uint64
// Deprecated: use InboundRTPPacketsJitter.
RTPPacketsJitter float64
// Deprecated: use InboundRTCPPackets.
RTCPPacketsReceived uint64
// Deprecated: use OutboundRTCPPackets.
RTCPPacketsSent uint64
// Deprecated: use InboundRTCPPacketsInError.
RTCPPacketsInError uint64
}
func sessionStatsFromMedias(mediaStats map[*description.Media]SessionStatsMedia) SessionStats {
inboundBytes := uint64(0)
outboundBytes := uint64(0)
inboundRTPPackets := uint64(0)
outboundRTPPackets := uint64(0)
inboundRTPPacketsLost := uint64(0)
inboundRTPPacketsInError := uint64(0)
inboundRTPPacketsJitter := float64(0)
inboundRTPPacketsJitterCount := float64(0)
inboundRTCPPackets := uint64(0)
outboundRTCPPackets := uint64(0)
inboundRTCPPacketsInError := uint64(0)
for _, ms := range mediaStats {
inboundBytes += ms.InboundBytes
outboundBytes += ms.OutboundBytes
inboundRTPPacketsInError += ms.InboundRTPPacketsInError
inboundRTCPPackets += ms.InboundRTCPPackets
outboundRTCPPackets += ms.OutboundRTCPPackets
inboundRTCPPacketsInError += ms.InboundRTCPPacketsInError
for _, fs := range ms.Formats {
inboundRTPPackets += fs.InboundRTPPackets
outboundRTPPackets += fs.OutboundRTPPackets
inboundRTPPacketsLost += fs.InboundRTPPacketsLost
inboundRTPPacketsJitter += fs.InboundRTPPacketsJitter
inboundRTPPacketsJitterCount++
}
}
if inboundRTPPacketsJitterCount != 0 {
inboundRTPPacketsJitter /= inboundRTPPacketsJitterCount
}
return SessionStats{
InboundBytes: inboundBytes,
InboundRTPPackets: inboundRTPPackets,
InboundRTPPacketsLost: inboundRTPPacketsLost,
InboundRTPPacketsInError: inboundRTPPacketsInError,
InboundRTPPacketsJitter: inboundRTPPacketsJitter,
InboundRTCPPackets: inboundRTCPPackets,
InboundRTCPPacketsInError: inboundRTCPPacketsInError,
OutboundBytes: outboundBytes,
OutboundRTPPackets: outboundRTPPackets,
OutboundRTCPPackets: outboundRTCPPackets,
Medias: mediaStats,
// deprecated
BytesReceived: inboundBytes,
BytesSent: outboundBytes,
RTPPacketsReceived: inboundRTPPackets,
RTPPacketsSent: outboundRTPPackets,
RTPPacketsLost: inboundRTPPacketsLost,
RTPPacketsInError: inboundRTPPacketsInError,
RTPPacketsJitter: inboundRTPPacketsJitter,
RTCPPacketsReceived: inboundRTCPPackets,
RTCPPacketsSent: outboundRTCPPackets,
RTCPPacketsInError: inboundRTCPPacketsInError,
}
}