Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ Mathis Engelbart <mathis.engelbart@gmail.com>
Max Hawkins <maxhawkins@gmail.com>
Sean DuBois <seaduboi@amazon.com>
Sean DuBois <sean@siobud.com>
seb-dev <sebapetit@protonmail.com>
Simone Gotti <simone.gotti@gmail.com>
Woodrow Douglass <wdouglass@carnegierobotics.com>
34 changes: 34 additions & 0 deletions receiver_report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ func TestReceiverReportUnmarshal(t *testing.T) {
ProfileExtensions: []byte{},
},
},
{
Name: "valid with negative totalLost",
Data: []byte{
// v=2, p=0, count=1, RR, len=7
0x81, 0xc9, 0x0, 0x7,
// ssrc=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,
// ssrc=0xbc5e9a40
0xbc, 0x5e, 0x9a, 0x40,
// fracLost=0, totalLost=-1
0x0, 0xff, 0xff, 0xff,
// lastSeq=0x46e1
0x0, 0x0, 0x46, 0xe1,
// jitter=273
0x0, 0x0, 0x1, 0x11,
// lsr=0x9f36432
0x9, 0xf3, 0x64, 0x32,
// delay=150137
0x0, 0x2, 0x4a, 0x79,
},
Want: ReceiverReport{
SSRC: 0x902f9e2e,
Reports: []ReceptionReport{{
SSRC: 0xbc5e9a40,
FractionLost: 0,
TotalLost: -1,
LastSequenceNumber: 0x46e1,
Jitter: 273,
LastSenderReport: 0x9f36432,
Delay: 150137,
}},
ProfileExtensions: []byte{},
},
},
{
Name: "valid with extension data",
Data: []byte{
Expand Down
25 changes: 19 additions & 6 deletions reception_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ type ReceptionReport struct {
FractionLost uint8
// The total number of RTP data packets from source SSRC that have
// been lost since the beginning of reception.
TotalLost uint32
// https://www.ietf.org/rfc/rfc3550.txt Section 6.4 and appendix A.3
// The total number of packets lost is a signed number and can be
// negative
TotalLost int32
// The low 16 bits contain the highest sequence number received in an
// RTP data packet from source SSRC, and the most significant 16
// bits extend that sequence number with the corresponding count of
Expand Down Expand Up @@ -71,13 +74,17 @@ func (r ReceptionReport) Marshal() ([]byte, error) {
rawPacket[fractionLostOffset] = r.FractionLost

// pack TotalLost into 24 bits
if r.TotalLost >= (1 << 25) {
// we first convert signed integer to unsigned before using bit operators
uTotalLost := uint32(r.TotalLost)
if uTotalLost&0xff800000 != 0xff800000 && uTotalLost&0xff800000 != 0 {
return nil, errInvalidTotalLost
}
// Convert int32 to int24
uTotalLost = uTotalLost&0x80000000>>8 | uTotalLost&0x007fffff
tlBytes := rawPacket[totalLostOffset:]
tlBytes[0] = byte(r.TotalLost >> 16)
tlBytes[1] = byte(r.TotalLost >> 8)
tlBytes[2] = byte(r.TotalLost)
tlBytes[0] = byte(uTotalLost >> 16)
tlBytes[1] = byte(uTotalLost >> 8)
tlBytes[2] = byte(uTotalLost)

binary.BigEndian.PutUint32(rawPacket[lastSeqOffset:], r.LastSequenceNumber)
binary.BigEndian.PutUint32(rawPacket[jitterOffset:], r.Jitter)
Expand Down Expand Up @@ -115,7 +122,13 @@ func (r *ReceptionReport) Unmarshal(rawPacket []byte) error {
r.FractionLost = rawPacket[fractionLostOffset]

tlBytes := rawPacket[totalLostOffset:]
r.TotalLost = uint32(tlBytes[2]) | uint32(tlBytes[1])<<8 | uint32(tlBytes[0])<<16
uTotalLost := uint32(tlBytes[2]) | uint32(tlBytes[1])<<8 | uint32(tlBytes[0])<<16
// test sign
ua := uTotalLost & 0x007fffff
if uTotalLost&0x00800000 == 0x00800000 {
ua |= 0xff800000
}
r.TotalLost = int32(ua)

r.LastSequenceNumber = binary.BigEndian.Uint32(rawPacket[lastSeqOffset:])
r.Jitter = binary.BigEndian.Uint32(rawPacket[jitterOffset:])
Expand Down