mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 23:26:54 +08:00
add number of lost packets to rtcp receiver reports
This commit is contained in:
@@ -18,6 +18,10 @@ type RtcpReceiver struct {
|
|||||||
sequenceNumberCycles uint16
|
sequenceNumberCycles uint16
|
||||||
lastSequenceNumber uint16
|
lastSequenceNumber uint16
|
||||||
lastSenderReportTime uint32
|
lastSenderReportTime uint32
|
||||||
|
totalLost uint32
|
||||||
|
totalLostSinceRR uint32
|
||||||
|
totalSinceRR uint32
|
||||||
|
firstRtpReceived bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New allocates a RtcpReceiver.
|
// New allocates a RtcpReceiver.
|
||||||
@@ -42,11 +46,27 @@ func (rr *RtcpReceiver) OnFrame(streamType base.StreamType, buf []byte) {
|
|||||||
// extract the sequence number of the first frame
|
// extract the sequence number of the first frame
|
||||||
sequenceNumber := uint16(buf[2])<<8 | uint16(buf[3])
|
sequenceNumber := uint16(buf[2])<<8 | uint16(buf[3])
|
||||||
|
|
||||||
|
if !rr.firstRtpReceived {
|
||||||
|
rr.firstRtpReceived = true
|
||||||
|
rr.totalSinceRR = 1
|
||||||
|
rr.lastSequenceNumber = sequenceNumber
|
||||||
|
|
||||||
|
} else {
|
||||||
|
diff := (sequenceNumber - rr.lastSequenceNumber)
|
||||||
|
|
||||||
|
if sequenceNumber != (rr.lastSequenceNumber + 1) {
|
||||||
|
rr.totalLost += uint32(diff) - 1
|
||||||
|
rr.totalLostSinceRR += uint32(diff) - 1
|
||||||
|
}
|
||||||
|
|
||||||
if sequenceNumber < rr.lastSequenceNumber {
|
if sequenceNumber < rr.lastSequenceNumber {
|
||||||
rr.sequenceNumberCycles += 1
|
rr.sequenceNumberCycles += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rr.totalSinceRR += uint32(diff)
|
||||||
rr.lastSequenceNumber = sequenceNumber
|
rr.lastSequenceNumber = sequenceNumber
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// we can afford to unmarshal all RTCP frames
|
// we can afford to unmarshal all RTCP frames
|
||||||
@@ -75,10 +95,21 @@ func (rr *RtcpReceiver) Report() []byte {
|
|||||||
SSRC: rr.senderSSRC,
|
SSRC: rr.senderSSRC,
|
||||||
LastSequenceNumber: uint32(rr.sequenceNumberCycles)<<16 | uint32(rr.lastSequenceNumber),
|
LastSequenceNumber: uint32(rr.sequenceNumberCycles)<<16 | uint32(rr.lastSequenceNumber),
|
||||||
LastSenderReport: rr.lastSenderReportTime,
|
LastSenderReport: rr.lastSenderReportTime,
|
||||||
|
FractionLost: func() uint8 {
|
||||||
|
f := float64(rr.totalLostSinceRR) / float64(rr.totalSinceRR)
|
||||||
|
|
||||||
|
// equivalent to taking the integer part after multiplying the
|
||||||
|
// loss fraction by 256
|
||||||
|
return uint8(f * 256)
|
||||||
|
}(),
|
||||||
|
TotalLost: rr.totalLost,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rr.totalLostSinceRR = 0
|
||||||
|
rr.totalSinceRR = 0
|
||||||
|
|
||||||
byts, _ := report.Marshal()
|
byts, _ := report.Marshal()
|
||||||
return byts
|
return byts
|
||||||
}
|
}
|
||||||
|
@@ -10,10 +10,20 @@ import (
|
|||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRtcpReceiver(t *testing.T) {
|
func TestRtcpReceiverBase(t *testing.T) {
|
||||||
v := uint32(0x65f83afb)
|
v := uint32(0x65f83afb)
|
||||||
rr := New(&v)
|
rr := New(&v)
|
||||||
|
|
||||||
|
srPkt := rtcp.SenderReport{
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
NTPTime: 0xe363887a17ced916,
|
||||||
|
RTPTime: 1287981738,
|
||||||
|
PacketCount: 714,
|
||||||
|
OctetCount: 859127,
|
||||||
|
}
|
||||||
|
byts, _ := srPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtcp, byts)
|
||||||
|
|
||||||
rtpPkt := rtp.Packet{
|
rtpPkt := rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
@@ -25,19 +35,9 @@ func TestRtcpReceiver(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Payload: []byte("\x00\x00"),
|
Payload: []byte("\x00\x00"),
|
||||||
}
|
}
|
||||||
byts, _ := rtpPkt.Marshal()
|
byts, _ = rtpPkt.Marshal()
|
||||||
rr.OnFrame(base.StreamTypeRtp, byts)
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
srPkt := rtcp.SenderReport{
|
|
||||||
SSRC: 0xba9da416,
|
|
||||||
NTPTime: 0xe363887a17ced916,
|
|
||||||
RTPTime: 1287981738,
|
|
||||||
PacketCount: 714,
|
|
||||||
OctetCount: 859127,
|
|
||||||
}
|
|
||||||
byts, _ = srPkt.Marshal()
|
|
||||||
rr.OnFrame(base.StreamTypeRtcp, byts)
|
|
||||||
|
|
||||||
res := rr.Report()
|
res := rr.Report()
|
||||||
|
|
||||||
expectedPkt := rtcp.ReceiverReport{
|
expectedPkt := rtcp.ReceiverReport{
|
||||||
@@ -45,20 +45,35 @@ func TestRtcpReceiver(t *testing.T) {
|
|||||||
Reports: []rtcp.ReceptionReport{
|
Reports: []rtcp.ReceptionReport{
|
||||||
{
|
{
|
||||||
SSRC: 0xba9da416,
|
SSRC: 0xba9da416,
|
||||||
LastSequenceNumber: uint32(946),
|
LastSequenceNumber: 946,
|
||||||
LastSenderReport: uint32(0x887a17ce),
|
LastSenderReport: 0x887a17ce,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expected, _ := expectedPkt.Marshal()
|
expected, _ := expectedPkt.Marshal()
|
||||||
require.Equal(t, expected, res)
|
require.Equal(t, expected, res)
|
||||||
|
}
|
||||||
|
|
||||||
rtpPkt = rtp.Packet{
|
func TestRtcpReceiverSequenceOverflow(t *testing.T) {
|
||||||
|
v := uint32(0x65f83afb)
|
||||||
|
rr := New(&v)
|
||||||
|
|
||||||
|
srPkt := rtcp.SenderReport{
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
NTPTime: 0xe363887a17ced916,
|
||||||
|
RTPTime: 1287981738,
|
||||||
|
PacketCount: 714,
|
||||||
|
OctetCount: 859127,
|
||||||
|
}
|
||||||
|
byts, _ := srPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtcp, byts)
|
||||||
|
|
||||||
|
rtpPkt := rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 945,
|
SequenceNumber: 0xffff,
|
||||||
Timestamp: 1287987768,
|
Timestamp: 1287987768,
|
||||||
SSRC: 0xba9da416,
|
SSRC: 0xba9da416,
|
||||||
},
|
},
|
||||||
@@ -67,18 +82,158 @@ func TestRtcpReceiver(t *testing.T) {
|
|||||||
byts, _ = rtpPkt.Marshal()
|
byts, _ = rtpPkt.Marshal()
|
||||||
rr.OnFrame(base.StreamTypeRtp, byts)
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
res = rr.Report()
|
rtpPkt = rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 0x0000,
|
||||||
|
Timestamp: 1287987768,
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
},
|
||||||
|
Payload: []byte("\x00\x00"),
|
||||||
|
}
|
||||||
|
byts, _ = rtpPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
expectedPkt = rtcp.ReceiverReport{
|
res := rr.Report()
|
||||||
|
|
||||||
|
expectedPkt := rtcp.ReceiverReport{
|
||||||
SSRC: 0x65f83afb,
|
SSRC: 0x65f83afb,
|
||||||
Reports: []rtcp.ReceptionReport{
|
Reports: []rtcp.ReceptionReport{
|
||||||
{
|
{
|
||||||
SSRC: 0xba9da416,
|
SSRC: 0xba9da416,
|
||||||
LastSequenceNumber: uint32(1<<16 | 945),
|
LastSequenceNumber: 1<<16 | 0x0000,
|
||||||
LastSenderReport: uint32(0x887a17ce),
|
LastSenderReport: 0x887a17ce,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expected, _ = expectedPkt.Marshal()
|
expected, _ := expectedPkt.Marshal()
|
||||||
|
require.Equal(t, expected, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRtcpReceiverPacketLost(t *testing.T) {
|
||||||
|
v := uint32(0x65f83afb)
|
||||||
|
rr := New(&v)
|
||||||
|
|
||||||
|
srPkt := rtcp.SenderReport{
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
NTPTime: 0xe363887a17ced916,
|
||||||
|
RTPTime: 1287981738,
|
||||||
|
PacketCount: 714,
|
||||||
|
OctetCount: 859127,
|
||||||
|
}
|
||||||
|
byts, _ := srPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtcp, byts)
|
||||||
|
|
||||||
|
rtpPkt := rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 0x0120,
|
||||||
|
Timestamp: 1287987768,
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
},
|
||||||
|
Payload: []byte("\x00\x00"),
|
||||||
|
}
|
||||||
|
byts, _ = rtpPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
|
rtpPkt = rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 0x0122,
|
||||||
|
Timestamp: 1287987768,
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
},
|
||||||
|
Payload: []byte("\x00\x00"),
|
||||||
|
}
|
||||||
|
byts, _ = rtpPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
|
res := rr.Report()
|
||||||
|
|
||||||
|
expectedPkt := rtcp.ReceiverReport{
|
||||||
|
SSRC: 0x65f83afb,
|
||||||
|
Reports: []rtcp.ReceptionReport{
|
||||||
|
{
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
LastSequenceNumber: 0x0122,
|
||||||
|
LastSenderReport: 0x887a17ce,
|
||||||
|
FractionLost: func() uint8 {
|
||||||
|
v := float64(1) / 3
|
||||||
|
return uint8(v * 256)
|
||||||
|
}(),
|
||||||
|
TotalLost: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected, _ := expectedPkt.Marshal()
|
||||||
|
require.Equal(t, expected, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRtcpReceiverSequenceOverflowPacketLost(t *testing.T) {
|
||||||
|
v := uint32(0x65f83afb)
|
||||||
|
rr := New(&v)
|
||||||
|
|
||||||
|
srPkt := rtcp.SenderReport{
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
NTPTime: 0xe363887a17ced916,
|
||||||
|
RTPTime: 1287981738,
|
||||||
|
PacketCount: 714,
|
||||||
|
OctetCount: 859127,
|
||||||
|
}
|
||||||
|
byts, _ := srPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtcp, byts)
|
||||||
|
|
||||||
|
rtpPkt := rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 0xffff,
|
||||||
|
Timestamp: 1287987768,
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
},
|
||||||
|
Payload: []byte("\x00\x00"),
|
||||||
|
}
|
||||||
|
byts, _ = rtpPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
|
rtpPkt = rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 0x0002,
|
||||||
|
Timestamp: 1287987768,
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
},
|
||||||
|
Payload: []byte("\x00\x00"),
|
||||||
|
}
|
||||||
|
byts, _ = rtpPkt.Marshal()
|
||||||
|
rr.OnFrame(base.StreamTypeRtp, byts)
|
||||||
|
|
||||||
|
res := rr.Report()
|
||||||
|
|
||||||
|
expectedPkt := rtcp.ReceiverReport{
|
||||||
|
SSRC: 0x65f83afb,
|
||||||
|
Reports: []rtcp.ReceptionReport{
|
||||||
|
{
|
||||||
|
SSRC: 0xba9da416,
|
||||||
|
LastSequenceNumber: 1<<16 | 0x0002,
|
||||||
|
LastSenderReport: 0x887a17ce,
|
||||||
|
FractionLost: func() uint8 {
|
||||||
|
v := float64(2) / 4
|
||||||
|
return uint8(v * 256)
|
||||||
|
}(),
|
||||||
|
TotalLost: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected, _ := expectedPkt.Marshal()
|
||||||
require.Equal(t, expected, res)
|
require.Equal(t, expected, res)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user