Skip to content
Merged
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
51 changes: 51 additions & 0 deletions packet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package rtcp

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -153,3 +154,53 @@ func TestUnmarshalMaxLengthRawPacket(t *testing.T) {
assert.True(t, ok)
assert.Equal(t, rawPacket, []byte(*parsed))
}

// Sender and receiver reports carry profile-specific extensions that are padded
// out to a whole 32-bit word, so both the header length field and MarshalSize
// have to account for that padding.
func TestReportProfileExtensionsRoundTrip(t *testing.T) {
for _, extLength := range []int{1, 4, 5, 8, 24} {
extensions := bytes.Repeat([]byte{0xab}, extLength)
padded := append(bytes.Repeat([]byte{0xab}, extLength), make([]byte, getPadding(extLength))...)
reports := []ReceptionReport{{SSRC: 2}}

receiverReport := &ReceiverReport{SSRC: 1, Reports: reports, ProfileExtensions: extensions}
senderReport := &SenderReport{SSRC: 1, Reports: reports, ProfileExtensions: extensions}

for _, test := range []struct {
Name string
Packet Packet
Header func() Header
Want Packet
}{
{
Name: "ReceiverReport",
Packet: receiverReport,
Header: receiverReport.Header,
Want: &ReceiverReport{SSRC: 1, Reports: reports, ProfileExtensions: padded},
},
{
Name: "SenderReport",
Packet: senderReport,
Header: senderReport.Header,
Want: &SenderReport{SSRC: 1, Reports: reports, ProfileExtensions: padded},
},
} {
data, err := test.Packet.Marshal()
assert.NoErrorf(t, err, "Marshal %s with %d extension bytes", test.Name, extLength)

assert.Lenf(t, data, test.Packet.MarshalSize(),
"MarshalSize %s with %d extension bytes", test.Name, extLength)
assert.Equalf(t, uint16(len(data)/4-1), test.Header().Length, //nolint:gosec // G115
"header length %s with %d extension bytes", test.Name, extLength)

packets, err := Unmarshal(data)
assert.NoErrorf(t, err, "Unmarshal %s with %d extension bytes", test.Name, extLength)
if !assert.Lenf(t, packets, 1, "packet count %s with %d extension bytes", test.Name, extLength) {
continue
}
assert.Equalf(t, test.Want, packets[0],
"round trip %s with %d extension bytes", test.Name, extLength)
}
}
}
19 changes: 7 additions & 12 deletions receiver_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,9 @@ func (r ReceiverReport) Marshal() ([]byte, error) {
return nil, errTooManyReports
}

pe := make([]byte, len(r.ProfileExtensions))
copy(pe, r.ProfileExtensions)

// if the length of the profile extensions isn't devisible
// by 4, we need to pad the end.
for (len(pe) & 0x3) != 0 {
pe = append(pe, 0) //nolint:makezero
}

rawPacket = append(rawPacket, pe...) //nolint:makezero
// The buffer is already sized for the profile extensions and their padding,
// so any trailing pad bytes are left as the zeroes MarshalSize allocated.
copy(packetBody[ssrcLength+receptionReportLength*len(r.Reports):], r.ProfileExtensions)

hData, err := r.Header().Marshal()
if err != nil {
Expand Down Expand Up @@ -166,15 +159,17 @@ func (r *ReceiverReport) MarshalSize() int {
repsLength += rep.len()
}

return headerLength + ssrcLength + repsLength
extLength := len(r.ProfileExtensions)

return headerLength + ssrcLength + repsLength + extLength + getPadding(extLength)
}

// Header returns the Header associated with this packet.
func (r *ReceiverReport) Header() Header {
return Header{
Count: uint8(len(r.Reports)), //nolint:gosec // G115
Type: TypeReceiverReport,
Length: uint16((r.MarshalSize()/4)-1) + uint16(getPadding(len(r.ProfileExtensions))), //nolint:gosec // G115
Length: uint16((r.MarshalSize() / 4) - 1), //nolint:gosec // G115
}
}

Expand Down
4 changes: 3 additions & 1 deletion sender_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ func (r *SenderReport) MarshalSize() int {
repsLength += rep.len()
}

return headerLength + srHeaderLength + repsLength + len(r.ProfileExtensions)
extLength := len(r.ProfileExtensions)

return headerLength + srHeaderLength + repsLength + extLength + getPadding(extLength)
}

// Header returns the Header associated with this packet.
Expand Down
Loading