add number of lost packets to rtcp receiver reports

This commit is contained in:
aler9
2020-11-21 15:55:04 +01:00
parent 300a57aef1
commit a21bced1dd
2 changed files with 210 additions and 24 deletions

View File

@@ -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,10 +46,26 @@ 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 sequenceNumber < rr.lastSequenceNumber { if !rr.firstRtpReceived {
rr.sequenceNumberCycles += 1 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 {
rr.sequenceNumberCycles += 1
}
rr.totalSinceRR += uint32(diff)
rr.lastSequenceNumber = sequenceNumber
} }
rr.lastSequenceNumber = sequenceNumber
} }
} else { } else {
@@ -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
} }

View File

@@ -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)
} }