Add Header() method to Packet

Simplifies the API. Unmarshal can now return one Packet value instead
of both a packet and a header.

Relates to #119
This commit is contained in:
Max Hawkins
2018-12-02 12:01:11 -08:00
committed by Woodrow Douglass
parent 5655d151b1
commit 0ef6602adb
9 changed files with 167 additions and 70 deletions

View File

@@ -30,14 +30,15 @@ func (g Goodbye) Marshal() ([]byte, error) {
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/ */
rawPacket := make([]byte, len(g.Sources)*ssrcLength) rawPacket := make([]byte, g.len())
packetBody := rawPacket[headerLength:]
if len(g.Sources) > countMax { if len(g.Sources) > countMax {
return nil, errTooManySources return nil, errTooManySources
} }
for i, s := range g.Sources { for i, s := range g.Sources {
binary.BigEndian.PutUint32(rawPacket[i*ssrcLength:], s) binary.BigEndian.PutUint32(packetBody[i*ssrcLength:], s)
} }
if g.Reason != "" { if g.Reason != "" {
@@ -47,25 +48,16 @@ func (g Goodbye) Marshal() ([]byte, error) {
return nil, errReasonTooLong return nil, errReasonTooLong
} }
rawPacket = append(rawPacket, uint8(len(reason))) reasonOffset := len(g.Sources) * ssrcLength
rawPacket = append(rawPacket, reason...) packetBody[reasonOffset] = uint8(len(reason))
copy(packetBody[reasonOffset+1:], reason)
// align to 32-bit boundary
rawPacket = append(rawPacket, make([]byte, util.GetPadding(len(rawPacket)))...)
} }
h := Header{ hData, err := g.Header().Marshal()
Padding: false,
Count: uint8(len(g.Sources)),
Type: TypeGoodbye,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(rawPacket, hData)
rawPacket = append(hData, rawPacket...)
return rawPacket, nil return rawPacket, nil
} }
@@ -126,3 +118,23 @@ func (g *Goodbye) Unmarshal(rawPacket []byte) error {
return nil return nil
} }
// Header returns the Header associated with this packet.
func (g *Goodbye) Header() Header {
return Header{
Padding: false,
Count: uint8(len(g.Sources)),
Type: TypeGoodbye,
Length: uint16((g.len() / 4) - 1),
}
}
func (g *Goodbye) len() int {
srcsLength := len(g.Sources) * ssrcLength
reasonLength := len(g.Reason) + 1
l := headerLength + srcsLength + reasonLength
// align to 32-bit boundary
return l + util.GetPadding(l)
}

View File

@@ -2,6 +2,8 @@ package rtcp
// Packet represents an RTCP packet, a protocol used for out-of-band statistics and control information for an RTP session // Packet represents an RTCP packet, a protocol used for out-of-band statistics and control information for an RTP session
type Packet interface { type Packet interface {
Header() Header
Marshal() ([]byte, error) Marshal() ([]byte, error)
Unmarshal(rawPacket []byte) error Unmarshal(rawPacket []byte) error
} }

View File

@@ -11,6 +11,8 @@ type PictureLossIndication struct {
// SSRC where the loss was experienced // SSRC where the loss was experienced
MediaSSRC uint32 MediaSSRC uint32
header Header
} }
const ( const (
@@ -26,9 +28,11 @@ func (p PictureLossIndication) Marshal() ([]byte, error) {
* *
* The semantics of this FB message is independent of the payload type. * The semantics of this FB message is independent of the payload type.
*/ */
rawPacket := make([]byte, 8) rawPacket := make([]byte, p.len())
binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC) packetBody := rawPacket[headerLength:]
binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
binary.BigEndian.PutUint32(packetBody, p.SenderSSRC)
binary.BigEndian.PutUint32(packetBody[4:], p.MediaSSRC)
h := Header{ h := Header{
Count: pliFMT, Count: pliFMT,
@@ -39,8 +43,9 @@ func (p PictureLossIndication) Marshal() ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(rawPacket, hData)
return append(hData, rawPacket...), nil return rawPacket, nil
} }
// Unmarshal decodes the PictureLossIndication from binary // Unmarshal decodes the PictureLossIndication from binary
@@ -62,3 +67,12 @@ func (p *PictureLossIndication) Unmarshal(rawPacket []byte) error {
p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:]) p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
return nil return nil
} }
// Header returns the Header associated with this packet.
func (p *PictureLossIndication) Header() Header {
return p.header
}
func (p *PictureLossIndication) len() int {
return headerLength + ssrcLength*2
}

View File

@@ -14,8 +14,10 @@ type RapidResynchronizationRequest struct {
} }
const ( const (
rrrFMT = 5 rrrFMT = 5
rrrLength = 2 rrrLength = 2
rrrHeaderLength = ssrcLength * 2
rrrMediaOffset = 4
) )
// Marshal encodes the RapidResynchronizationRequest in binary // Marshal encodes the RapidResynchronizationRequest in binary
@@ -26,21 +28,19 @@ func (p RapidResynchronizationRequest) Marshal() ([]byte, error) {
* *
* The semantics of this FB message is independent of the payload type. * The semantics of this FB message is independent of the payload type.
*/ */
rawPacket := make([]byte, 8) rawPacket := make([]byte, p.len())
binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC) packetBody := rawPacket[headerLength:]
binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
h := Header{ binary.BigEndian.PutUint32(packetBody, p.SenderSSRC)
Count: rrrFMT, binary.BigEndian.PutUint32(packetBody[rrrMediaOffset:], p.MediaSSRC)
Type: TypeTransportSpecificFeedback,
Length: rrrLength, hData, err := p.Header().Marshal()
}
hData, err := h.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(rawPacket, hData)
return append(hData, rawPacket...), nil return rawPacket, nil
} }
// Unmarshal decodes the RapidResynchronizationRequest from binary // Unmarshal decodes the RapidResynchronizationRequest from binary
@@ -63,3 +63,16 @@ func (p *RapidResynchronizationRequest) Unmarshal(rawPacket []byte) error {
p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:]) p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
return nil return nil
} }
func (p *RapidResynchronizationRequest) len() int {
return headerLength + rrrHeaderLength
}
// Header returns the Header associated with this packet.
func (p *RapidResynchronizationRequest) Header() Header {
return Header{
Count: rrrFMT,
Type: TypeTransportSpecificFeedback,
Length: rrrLength,
}
}

View File

@@ -23,3 +23,12 @@ func (r *RawPacket) Unmarshal(b []byte) error {
return nil return nil
} }
// Header returns the Header associated with this packet.
func (r RawPacket) Header() Header {
var h Header
if err := h.Unmarshal(r); err != nil {
return Header{}
}
return h
}

View File

@@ -49,33 +49,29 @@ func (r ReceiverReport) Marshal() ([]byte, error) {
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/ */
rawPacket := make([]byte, ssrcLength) rawPacket := make([]byte, r.len())
packetBody := rawPacket[headerLength:]
binary.BigEndian.PutUint32(rawPacket, r.SSRC) binary.BigEndian.PutUint32(packetBody, r.SSRC)
for _, rp := range r.Reports { for i, rp := range r.Reports {
data, err := rp.Marshal() data, err := rp.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
rawPacket = append(rawPacket, data...) offset := ssrcLength + receptionReportLength*i
copy(packetBody[offset:], data)
} }
if len(r.Reports) > countMax { if len(r.Reports) > countMax {
return nil, errTooManyReports return nil, errTooManyReports
} }
h := Header{ hData, err := r.Header().Marshal()
Count: uint8(len(r.Reports)),
Type: TypeReceiverReport,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(rawPacket, hData)
rawPacket = append(hData, rawPacket...)
return rawPacket, nil return rawPacket, nil
} }
@@ -139,3 +135,20 @@ func (r *ReceiverReport) Unmarshal(rawPacket []byte) error {
return nil return nil
} }
func (r *ReceiverReport) len() int {
repsLength := 0
for _, rep := range r.Reports {
repsLength += rep.len()
}
return headerLength + ssrcLength + repsLength
}
// Header returns the Header associated with this packet.
func (r *ReceiverReport) Header() Header {
return Header{
Count: uint8(len(r.Reports)),
Type: TypeReceiverReport,
Length: uint16((r.len() / 4) - 1),
}
}

View File

@@ -124,3 +124,7 @@ func (r *ReceptionReport) Unmarshal(rawPacket []byte) error {
return nil return nil
} }
func (r *ReceptionReport) len() int {
return receptionReportLength
}

View File

@@ -31,6 +31,8 @@ type SenderReport struct {
// block conveys statistics on the reception of RTP packets from a // block conveys statistics on the reception of RTP packets from a
// single synchronization source. // single synchronization source.
Reports []ReceptionReport Reports []ReceptionReport
header Header
} }
var ( var (
@@ -87,37 +89,33 @@ func (r SenderReport) Marshal() ([]byte, error) {
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/ */
rawPacket := make([]byte, srHeaderLength) rawPacket := make([]byte, r.len())
packetBody := rawPacket[headerLength:]
binary.BigEndian.PutUint32(rawPacket[srSSRCOffset:], r.SSRC) binary.BigEndian.PutUint32(packetBody[srSSRCOffset:], r.SSRC)
binary.BigEndian.PutUint64(rawPacket[srNTPOffset:], r.NTPTime) binary.BigEndian.PutUint64(packetBody[srNTPOffset:], r.NTPTime)
binary.BigEndian.PutUint32(rawPacket[srRTPOffset:], r.RTPTime) binary.BigEndian.PutUint32(packetBody[srRTPOffset:], r.RTPTime)
binary.BigEndian.PutUint32(rawPacket[srPacketCountOffset:], r.PacketCount) binary.BigEndian.PutUint32(packetBody[srPacketCountOffset:], r.PacketCount)
binary.BigEndian.PutUint32(rawPacket[srOctetCountOffset:], r.OctetCount) binary.BigEndian.PutUint32(packetBody[srOctetCountOffset:], r.OctetCount)
for _, rp := range r.Reports { for i, rp := range r.Reports {
data, err := rp.Marshal() data, err := rp.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
rawPacket = append(rawPacket, data...) offset := srHeaderLength + receptionReportLength*i
copy(packetBody[offset:], data)
} }
if len(r.Reports) > countMax { if len(r.Reports) > countMax {
return nil, errTooManyReports return nil, errTooManyReports
} }
h := Header{ hData, err := r.Header().Marshal()
Count: uint8(len(r.Reports)),
Type: TypeSenderReport,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(rawPacket, hData)
rawPacket = append(hData, rawPacket...)
return rawPacket, nil return rawPacket, nil
} }
@@ -197,3 +195,20 @@ func (r *SenderReport) Unmarshal(rawPacket []byte) error {
return nil return nil
} }
func (r *SenderReport) len() int {
repsLength := 0
for _, rep := range r.Reports {
repsLength += rep.len()
}
return headerLength + srHeaderLength + repsLength
}
// Header returns the Header associated with this packet.
func (r *SenderReport) Header() Header {
return Header{
Count: uint8(len(r.Reports)),
Type: TypeSenderReport,
Length: uint16((r.len() / 4) - 1),
}
}

View File

@@ -82,30 +82,28 @@ func (s SourceDescription) Marshal() ([]byte, error) {
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*/ */
rawPacket := make([]byte, 0) rawPacket := make([]byte, s.len())
packetBody := rawPacket[headerLength:]
chunkOffset := 0
for _, c := range s.Chunks { for _, c := range s.Chunks {
data, err := c.Marshal() data, err := c.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
rawPacket = append(rawPacket, data...) copy(packetBody[chunkOffset:], data)
chunkOffset += len(data)
} }
if len(s.Chunks) > countMax { if len(s.Chunks) > countMax {
return nil, errTooManyChunks return nil, errTooManyChunks
} }
h := Header{ hData, err := s.Header().Marshal()
Count: uint8(len(s.Chunks)),
Type: TypeSourceDescription,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(rawPacket, hData)
rawPacket = append(hData, rawPacket...)
return rawPacket, nil return rawPacket, nil
} }
@@ -156,6 +154,23 @@ func (s *SourceDescription) Unmarshal(rawPacket []byte) error {
return nil return nil
} }
func (s *SourceDescription) len() int {
chunksLength := 0
for _, c := range s.Chunks {
chunksLength += c.len()
}
return headerLength + chunksLength
}
// Header returns the Header associated with this packet.
func (s *SourceDescription) Header() Header {
return Header{
Count: uint8(len(s.Chunks)),
Type: TypeSourceDescription,
Length: uint16((s.len() / 4) - 1),
}
}
// A SourceDescriptionChunk contains items describing a single RTP source // A SourceDescriptionChunk contains items describing a single RTP source
type SourceDescriptionChunk struct { type SourceDescriptionChunk struct {
// The source (ssrc) or contributing source (csrc) identifier this packet describes // The source (ssrc) or contributing source (csrc) identifier this packet describes