diff --git a/pkg/rtcp/packet.go b/pkg/rtcp/packet.go index ab71ba66..f43f1fe9 100644 --- a/pkg/rtcp/packet.go +++ b/pkg/rtcp/packet.go @@ -36,10 +36,9 @@ func Unmarshal(rawPacket []byte) (Packet, Header, error) { p = new(PictureLossIndication) default: - return nil, h, errWrongType + p = new(RawPacket) } err = p.Unmarshal(rawPacket) return p, h, err - } diff --git a/pkg/rtcp/raw_packet.go b/pkg/rtcp/raw_packet.go new file mode 100644 index 00000000..1556b381 --- /dev/null +++ b/pkg/rtcp/raw_packet.go @@ -0,0 +1,25 @@ +package rtcp + +// RawPacket represents an unparsed RTCP packet. It's returned by Unmarshal when +// a packet with an unknown type is encountered. +type RawPacket []byte + +// Marshal encodes the packet in binary. +func (r RawPacket) Marshal() ([]byte, error) { + return r, nil +} + +// Unmarshal decodes the packet from binary. +func (r *RawPacket) Unmarshal(b []byte) error { + if len(b) < (headerLength) { + return errPacketTooShort + } + *r = b + + var h Header + if err := h.Unmarshal(b); err != nil { + return err + } + + return nil +} diff --git a/pkg/rtcp/raw_packet_test.go b/pkg/rtcp/raw_packet_test.go new file mode 100644 index 00000000..f48ca70a --- /dev/null +++ b/pkg/rtcp/raw_packet_test.go @@ -0,0 +1,61 @@ +package rtcp + +import ( + "reflect" + "testing" +) + +func TestRawPacketRoundTrip(t *testing.T) { + for _, test := range []struct { + Name string + Packet RawPacket + WantMarshalError error + WantUnmarshalError error + }{ + { + Name: "valid", + Packet: RawPacket([]byte{ + // v=2, p=0, count=1, BYE, len=12 + 0x81, 0xcb, 0x00, 0x0c, + // ssrc=0x902f9e2e + 0x90, 0x2f, 0x9e, 0x2e, + // len=3, text=FOO + 0x03, 0x46, 0x4f, 0x4f, + }), + }, + { + Name: "short header", + Packet: RawPacket([]byte{0x00}), + WantUnmarshalError: errPacketTooShort, + }, + { + Name: "invalid header", + Packet: RawPacket([]byte{ + // v=0, p=0, count=0, RR, len=4 + 0x00, 0xc9, 0x00, 0x04, + }), + WantUnmarshalError: errBadVersion, + }, + } { + data, err := test.Packet.Marshal() + if got, want := err, test.WantMarshalError; got != want { + t.Fatalf("Marshal %q: err = %v, want %v", test.Name, got, want) + } + if err != nil { + continue + } + + var decoded RawPacket + err = decoded.Unmarshal(data) + if got, want := err, test.WantUnmarshalError; got != want { + t.Fatalf("Unmarshal %q: err = %v, want %v", test.Name, got, want) + } + if err != nil { + continue + } + + if got, want := decoded, test.Packet; !reflect.DeepEqual(got, want) { + t.Fatalf("%q raw round trip: got %#v, want %#v", test.Name, got, want) + } + } +}