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 {
return nil, errTooManySources
}
for i, s := range g.Sources {
binary.BigEndian.PutUint32(rawPacket[i*ssrcLength:], s)
binary.BigEndian.PutUint32(packetBody[i*ssrcLength:], s)
}
if g.Reason != "" {
@@ -47,25 +48,16 @@ func (g Goodbye) Marshal() ([]byte, error) {
return nil, errReasonTooLong
}
rawPacket = append(rawPacket, uint8(len(reason)))
rawPacket = append(rawPacket, reason...)
// align to 32-bit boundary
rawPacket = append(rawPacket, make([]byte, util.GetPadding(len(rawPacket)))...)
reasonOffset := len(g.Sources) * ssrcLength
packetBody[reasonOffset] = uint8(len(reason))
copy(packetBody[reasonOffset+1:], reason)
}
h := Header{
Padding: false,
Count: uint8(len(g.Sources)),
Type: TypeGoodbye,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
hData, err := g.Header().Marshal()
if err != nil {
return nil, err
}
rawPacket = append(hData, rawPacket...)
copy(rawPacket, hData)
return rawPacket, nil
}
@@ -126,3 +118,23 @@ func (g *Goodbye) Unmarshal(rawPacket []byte) error {
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
type Packet interface {
Header() Header
Marshal() ([]byte, error)
Unmarshal(rawPacket []byte) error
}

View File

@@ -11,6 +11,8 @@ type PictureLossIndication struct {
// SSRC where the loss was experienced
MediaSSRC uint32
header Header
}
const (
@@ -26,9 +28,11 @@ func (p PictureLossIndication) Marshal() ([]byte, error) {
*
* The semantics of this FB message is independent of the payload type.
*/
rawPacket := make([]byte, 8)
binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
rawPacket := make([]byte, p.len())
packetBody := rawPacket[headerLength:]
binary.BigEndian.PutUint32(packetBody, p.SenderSSRC)
binary.BigEndian.PutUint32(packetBody[4:], p.MediaSSRC)
h := Header{
Count: pliFMT,
@@ -39,8 +43,9 @@ func (p PictureLossIndication) Marshal() ([]byte, error) {
if err != nil {
return nil, err
}
copy(rawPacket, hData)
return append(hData, rawPacket...), nil
return rawPacket, nil
}
// 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:])
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

@@ -16,6 +16,8 @@ type RapidResynchronizationRequest struct {
const (
rrrFMT = 5
rrrLength = 2
rrrHeaderLength = ssrcLength * 2
rrrMediaOffset = 4
)
// 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.
*/
rawPacket := make([]byte, 8)
binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
rawPacket := make([]byte, p.len())
packetBody := rawPacket[headerLength:]
h := Header{
Count: rrrFMT,
Type: TypeTransportSpecificFeedback,
Length: rrrLength,
}
hData, err := h.Marshal()
binary.BigEndian.PutUint32(packetBody, p.SenderSSRC)
binary.BigEndian.PutUint32(packetBody[rrrMediaOffset:], p.MediaSSRC)
hData, err := p.Header().Marshal()
if err != nil {
return nil, err
}
copy(rawPacket, hData)
return append(hData, rawPacket...), nil
return rawPacket, nil
}
// 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:])
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
}
// 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()
if err != nil {
return nil, err
}
rawPacket = append(rawPacket, data...)
offset := ssrcLength + receptionReportLength*i
copy(packetBody[offset:], data)
}
if len(r.Reports) > countMax {
return nil, errTooManyReports
}
h := Header{
Count: uint8(len(r.Reports)),
Type: TypeReceiverReport,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
hData, err := r.Header().Marshal()
if err != nil {
return nil, err
}
rawPacket = append(hData, rawPacket...)
copy(rawPacket, hData)
return rawPacket, nil
}
@@ -139,3 +135,20 @@ func (r *ReceiverReport) Unmarshal(rawPacket []byte) error {
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
}
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
// single synchronization source.
Reports []ReceptionReport
header Header
}
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.PutUint64(rawPacket[srNTPOffset:], r.NTPTime)
binary.BigEndian.PutUint32(rawPacket[srRTPOffset:], r.RTPTime)
binary.BigEndian.PutUint32(rawPacket[srPacketCountOffset:], r.PacketCount)
binary.BigEndian.PutUint32(rawPacket[srOctetCountOffset:], r.OctetCount)
binary.BigEndian.PutUint32(packetBody[srSSRCOffset:], r.SSRC)
binary.BigEndian.PutUint64(packetBody[srNTPOffset:], r.NTPTime)
binary.BigEndian.PutUint32(packetBody[srRTPOffset:], r.RTPTime)
binary.BigEndian.PutUint32(packetBody[srPacketCountOffset:], r.PacketCount)
binary.BigEndian.PutUint32(packetBody[srOctetCountOffset:], r.OctetCount)
for _, rp := range r.Reports {
for i, rp := range r.Reports {
data, err := rp.Marshal()
if err != nil {
return nil, err
}
rawPacket = append(rawPacket, data...)
offset := srHeaderLength + receptionReportLength*i
copy(packetBody[offset:], data)
}
if len(r.Reports) > countMax {
return nil, errTooManyReports
}
h := Header{
Count: uint8(len(r.Reports)),
Type: TypeSenderReport,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
hData, err := r.Header().Marshal()
if err != nil {
return nil, err
}
rawPacket = append(hData, rawPacket...)
copy(rawPacket, hData)
return rawPacket, nil
}
@@ -197,3 +195,20 @@ func (r *SenderReport) Unmarshal(rawPacket []byte) error {
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 {
data, err := c.Marshal()
if err != nil {
return nil, err
}
rawPacket = append(rawPacket, data...)
copy(packetBody[chunkOffset:], data)
chunkOffset += len(data)
}
if len(s.Chunks) > countMax {
return nil, errTooManyChunks
}
h := Header{
Count: uint8(len(s.Chunks)),
Type: TypeSourceDescription,
Length: uint16(((headerLength + len(rawPacket)) / 4) - 1),
}
hData, err := h.Marshal()
hData, err := s.Header().Marshal()
if err != nil {
return nil, err
}
rawPacket = append(hData, rawPacket...)
copy(rawPacket, hData)
return rawPacket, nil
}
@@ -156,6 +154,23 @@ func (s *SourceDescription) Unmarshal(rawPacket []byte) error {
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
type SourceDescriptionChunk struct {
// The source (ssrc) or contributing source (csrc) identifier this packet describes