mirror of
https://github.com/pion/webrtc.git
synced 2025-10-15 11:40:53 +08:00
Add RTCP Messages
*Avoid a type switch in srtp.go *Add support for transport layer nack and slice loss indication messages *Add String() functions for several RTCP packets to aid in debugging *Add support for transparent profile extensions to ReceiverReport messages Relates to #119
This commit is contained in:

committed by
Woodrow Douglass

parent
0ef6602adb
commit
f62abe50e8
@@ -56,7 +56,7 @@ func handleRTCP(getBufferTransports func(uint32) *TransportPair, buffer []byte)
|
||||
//decrypted packets can also be compound packets, so we have to nest our reader loop here.
|
||||
compoundPacket := rtcp.NewReader(bytes.NewReader(buffer))
|
||||
for {
|
||||
header, rawrtcp, err := compoundPacket.ReadPacket()
|
||||
_, rawrtcp, err := compoundPacket.ReadPacket()
|
||||
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
@@ -67,7 +67,7 @@ func handleRTCP(getBufferTransports func(uint32) *TransportPair, buffer []byte)
|
||||
}
|
||||
|
||||
var report rtcp.Packet
|
||||
report, header, err = rtcp.Unmarshal(rawrtcp)
|
||||
report, _, err = rtcp.Unmarshal(rawrtcp)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
@@ -83,28 +83,9 @@ func handleRTCP(getBufferTransports func(uint32) *TransportPair, buffer []byte)
|
||||
}
|
||||
}
|
||||
|
||||
switch header.Type {
|
||||
case rtcp.TypeSenderReport:
|
||||
for _, ssrc := range report.(*rtcp.SenderReport).Reports {
|
||||
f(ssrc.SSRC)
|
||||
}
|
||||
case rtcp.TypeReceiverReport:
|
||||
for _, ssrc := range report.(*rtcp.ReceiverReport).Reports {
|
||||
f(ssrc.SSRC)
|
||||
}
|
||||
case rtcp.TypeSourceDescription:
|
||||
for _, ssrc := range report.(*rtcp.SourceDescription).Chunks {
|
||||
f(ssrc.Source)
|
||||
}
|
||||
case rtcp.TypeGoodbye:
|
||||
for _, ssrc := range report.(*rtcp.Goodbye).Sources {
|
||||
for _, ssrc := range report.DestinationSSRC() {
|
||||
f(ssrc)
|
||||
}
|
||||
case rtcp.TypeTransportSpecificFeedback:
|
||||
f(report.(*rtcp.RapidResynchronizationRequest).MediaSSRC)
|
||||
case rtcp.TypePayloadSpecificFeedback:
|
||||
f(report.(*rtcp.PictureLossIndication).MediaSSRC)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -138,3 +138,10 @@ func (g *Goodbye) len() int {
|
||||
// align to 32-bit boundary
|
||||
return l + util.GetPadding(l)
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (g *Goodbye) DestinationSSRC() []uint32 {
|
||||
out := make([]uint32, len(g.Sources))
|
||||
copy(out, g.Sources)
|
||||
return out
|
||||
}
|
||||
|
@@ -3,6 +3,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
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
DestinationSSRC() []uint32
|
||||
|
||||
Marshal() ([]byte, error)
|
||||
Unmarshal(rawPacket []byte) error
|
||||
@@ -32,10 +34,24 @@ func Unmarshal(rawPacket []byte) (Packet, Header, error) {
|
||||
p = new(Goodbye)
|
||||
|
||||
case TypeTransportSpecificFeedback:
|
||||
switch h.Count {
|
||||
case tlnFMT:
|
||||
p = new(TransportLayerNack)
|
||||
case rrrFMT:
|
||||
p = new(RapidResynchronizationRequest)
|
||||
default:
|
||||
p = new(RawPacket)
|
||||
}
|
||||
|
||||
case TypePayloadSpecificFeedback:
|
||||
switch h.Count {
|
||||
case pliFMT:
|
||||
p = new(PictureLossIndication)
|
||||
case sliFMT:
|
||||
p = new(SliceLossIndication)
|
||||
default:
|
||||
p = new(RawPacket)
|
||||
}
|
||||
|
||||
default:
|
||||
p = new(RawPacket)
|
||||
|
@@ -2,6 +2,7 @@ package rtcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// The PictureLossIndication packet informs the encoder about the loss of an undefined amount of coded video data belonging to one or more pictures
|
||||
@@ -76,3 +77,12 @@ func (p *PictureLossIndication) Header() Header {
|
||||
func (p *PictureLossIndication) len() int {
|
||||
return headerLength + ssrcLength*2
|
||||
}
|
||||
|
||||
func (p *PictureLossIndication) String() string {
|
||||
return fmt.Sprintf("PictureLossIndication %x %x", p.SenderSSRC, p.MediaSSRC)
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (p *PictureLossIndication) DestinationSSRC() []uint32 {
|
||||
return []uint32{p.MediaSSRC}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package rtcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// The RapidResynchronizationRequest packet informs the encoder about the loss of an undefined amount of coded video data belonging to one or more pictures
|
||||
@@ -76,3 +77,12 @@ func (p *RapidResynchronizationRequest) Header() Header {
|
||||
Length: rrrLength,
|
||||
}
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (p *RapidResynchronizationRequest) DestinationSSRC() []uint32 {
|
||||
return []uint32{p.MediaSSRC}
|
||||
}
|
||||
|
||||
func (p *RapidResynchronizationRequest) String() string {
|
||||
return fmt.Sprintf("RapidResynchronizationRequest %x %x", p.SenderSSRC, p.MediaSSRC)
|
||||
}
|
||||
|
@@ -32,3 +32,8 @@ func (r RawPacket) Header() Header {
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (r *RawPacket) DestinationSSRC() []uint32 {
|
||||
return []uint32{}
|
||||
}
|
||||
|
@@ -96,6 +96,7 @@ func TestUnmarshal(t *testing.T) {
|
||||
LastSenderReport: 0x9f36432,
|
||||
Delay: 150137,
|
||||
}},
|
||||
ProfileExtensions: []uint8{},
|
||||
}
|
||||
if got, want := wantRR, parsed; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Unmarshal rr: got %#v, want %#v", got, want)
|
||||
|
@@ -1,6 +1,9 @@
|
||||
package rtcp
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A ReceiverReport (RR) packet provides reception quality feedback for an RTP stream
|
||||
type ReceiverReport struct {
|
||||
@@ -11,6 +14,8 @@ type ReceiverReport struct {
|
||||
// block conveys statistics on the reception of RTP packets from a
|
||||
// single synchronization source.
|
||||
Reports []ReceptionReport
|
||||
// extra data from the end of the packet; the application can parse this if needed.
|
||||
ProfileExtensions []byte
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -67,7 +72,10 @@ func (r ReceiverReport) Marshal() ([]byte, error) {
|
||||
return nil, errTooManyReports
|
||||
}
|
||||
|
||||
rawPacket = append(rawPacket, r.ProfileExtensions...)
|
||||
|
||||
hData, err := r.Header().Marshal()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -128,6 +136,7 @@ func (r *ReceiverReport) Unmarshal(rawPacket []byte) error {
|
||||
}
|
||||
r.Reports = append(r.Reports, rr)
|
||||
}
|
||||
r.ProfileExtensions = rawPacket[rrReportOffset+(len(r.Reports)*receptionReportLength):]
|
||||
|
||||
if uint8(len(r.Reports)) != h.Count {
|
||||
return errInvalidHeader
|
||||
@@ -152,3 +161,22 @@ func (r *ReceiverReport) Header() Header {
|
||||
Length: uint16((r.len() / 4) - 1),
|
||||
}
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (r *ReceiverReport) DestinationSSRC() []uint32 {
|
||||
out := make([]uint32, len(r.Reports))
|
||||
for i, v := range r.Reports {
|
||||
out[i] = v.SSRC
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (r ReceiverReport) String() string {
|
||||
out := fmt.Sprintf("ReceiverReport from %x\n", r.SSRC)
|
||||
out += fmt.Sprintf("\tSSRC \tLost\tLastSequence\n")
|
||||
for _, i := range r.Reports {
|
||||
out += fmt.Sprintf("\t%x\t%d/%d\t%d\n", i.SSRC, i.FractionLost, i.TotalLost, i.LastSequenceNumber)
|
||||
}
|
||||
out += fmt.Sprintf("\tProfile Extension Data: %v\n", r.ProfileExtensions)
|
||||
return out
|
||||
}
|
||||
|
@@ -43,6 +43,7 @@ func TestReceiverReportUnmarshal(t *testing.T) {
|
||||
LastSenderReport: 0x9f36432,
|
||||
Delay: 150137,
|
||||
}},
|
||||
ProfileExtensions: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -79,6 +80,9 @@ func TestReceiverReportUnmarshal(t *testing.T) {
|
||||
LastSenderReport: 0x9f36432,
|
||||
Delay: 150137,
|
||||
}},
|
||||
ProfileExtensions: []uint8{
|
||||
0x54, 0x45, 0x53, 0x54,
|
||||
0x44, 0x41, 0x54, 0x41},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -147,14 +151,14 @@ func TestReceiverReportUnmarshal(t *testing.T) {
|
||||
var rr ReceiverReport
|
||||
err := rr.Unmarshal(test.Data)
|
||||
if got, want := err, test.WantError; got != want {
|
||||
t.Fatalf("Unmarshal %q rr: err = %v, want %v", test.Name, got, want)
|
||||
t.Fatalf("Unmarshal %q rr: err = %#v, want %#v", test.Name, got, want)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if got, want := rr, test.Want; !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("Unmarshal %q rr: got %v, want %v", test.Name, got, want)
|
||||
t.Fatalf("Unmarshal %q rr: got %#v, want %#v", test.Name, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,6 +187,7 @@ func TestReceiverReportRoundTrip(t *testing.T) {
|
||||
SSRC: 0,
|
||||
},
|
||||
},
|
||||
ProfileExtensions: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -200,6 +205,7 @@ func TestReceiverReportRoundTrip(t *testing.T) {
|
||||
Delay: 46,
|
||||
},
|
||||
},
|
||||
ProfileExtensions: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -223,7 +229,7 @@ func TestReceiverReportRoundTrip(t *testing.T) {
|
||||
} {
|
||||
data, err := test.Report.Marshal()
|
||||
if got, want := err, test.WantError; got != want {
|
||||
t.Fatalf("Marshal %q: err = %v, want %v", test.Name, got, want)
|
||||
t.Fatalf("Marshal %q: err = %#v, want %#v", test.Name, got, want)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
@@ -231,7 +237,7 @@ func TestReceiverReportRoundTrip(t *testing.T) {
|
||||
|
||||
var decoded ReceiverReport
|
||||
if err := decoded.Unmarshal(data); err != nil {
|
||||
t.Fatalf("Unmarshal %q: %v", test.Name, err)
|
||||
t.Fatalf("Unmarshal %q: %#v", test.Name, err)
|
||||
}
|
||||
|
||||
if got, want := decoded, test.Report; !reflect.DeepEqual(got, want) {
|
||||
|
@@ -31,8 +31,6 @@ type SenderReport struct {
|
||||
// block conveys statistics on the reception of RTP packets from a
|
||||
// single synchronization source.
|
||||
Reports []ReceptionReport
|
||||
|
||||
header Header
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -196,6 +194,15 @@ func (r *SenderReport) Unmarshal(rawPacket []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (r *SenderReport) DestinationSSRC() []uint32 {
|
||||
out := make([]uint32, len(r.Reports))
|
||||
for i, v := range r.Reports {
|
||||
out[i] = v.SSRC
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *SenderReport) len() int {
|
||||
repsLength := 0
|
||||
for _, rep := range r.Reports {
|
||||
|
115
pkg/rtcp/slice_loss_indication.go
Normal file
115
pkg/rtcp/slice_loss_indication.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package rtcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// The SliceLossIndication packet informs the encoder about the loss of a picture slice
|
||||
type SliceLossIndication struct {
|
||||
// SSRC of sender
|
||||
SenderSSRC uint32
|
||||
|
||||
// SSRC of the media source
|
||||
MediaSSRC uint32
|
||||
|
||||
SLI []struct {
|
||||
// ID of first lost slice
|
||||
First uint16
|
||||
|
||||
// Number of lost slices
|
||||
Number uint16
|
||||
|
||||
// ID of related picture
|
||||
Picture uint8
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
sliFMT = 2
|
||||
sliLength = 2
|
||||
sliOffset = 8
|
||||
)
|
||||
|
||||
// Marshal encodes the SliceLossIndication in binary
|
||||
func (p SliceLossIndication) Marshal() ([]byte, error) {
|
||||
|
||||
if len(p.SLI)+sliLength > math.MaxUint8 {
|
||||
return nil, errTooManyReports
|
||||
}
|
||||
|
||||
rawPacket := make([]byte, sliOffset+(len(p.SLI)*4))
|
||||
binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
|
||||
binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
|
||||
for i := 0; i < len(p.SLI); i++ {
|
||||
sli := ((uint32(p.SLI[i].First) & 0x1FFF) << 19) |
|
||||
((uint32(p.SLI[i].Number) & 0x1FFF) << 6) |
|
||||
(uint32(p.SLI[i].Picture) & 0x3F)
|
||||
binary.BigEndian.PutUint32(rawPacket[sliOffset+(4*i):], sli)
|
||||
}
|
||||
h := Header{
|
||||
Count: tlnFMT,
|
||||
Type: TypeTransportSpecificFeedback,
|
||||
Length: uint16(tlnLength + len(p.SLI)),
|
||||
}
|
||||
hData, err := h.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return append(hData, rawPacket...), nil
|
||||
}
|
||||
|
||||
// Unmarshal decodes the SliceLossIndication from binary
|
||||
func (p *SliceLossIndication) Unmarshal(rawPacket []byte) error {
|
||||
var h Header
|
||||
if err := h.Unmarshal(rawPacket); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(rawPacket) < (headerLength + int(4*h.Length)) {
|
||||
return errPacketTooShort
|
||||
}
|
||||
|
||||
if h.Type != TypeTransportSpecificFeedback || h.Count != tlnFMT {
|
||||
return errWrongType
|
||||
}
|
||||
|
||||
p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
|
||||
p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
|
||||
for i := headerLength + sliOffset; i < (headerLength + int(h.Length*4)); i += 4 {
|
||||
sli := binary.BigEndian.Uint32(rawPacket[i:])
|
||||
p.SLI = append(p.SLI, struct {
|
||||
First uint16
|
||||
Number uint16
|
||||
Picture uint8
|
||||
}{
|
||||
uint16((sli >> 19) & 0x1FFF),
|
||||
uint16((sli >> 6) & 0x1FFF),
|
||||
uint8(sli & 0x3F)})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *SliceLossIndication) len() int {
|
||||
return headerLength + sliOffset + (len(p.SLI) * 4)
|
||||
}
|
||||
|
||||
// Header returns the Header associated with this packet.
|
||||
func (p *SliceLossIndication) Header() Header {
|
||||
return Header{
|
||||
Count: sliFMT,
|
||||
Type: TypeTransportSpecificFeedback,
|
||||
Length: uint16((p.len() / 4) - 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *SliceLossIndication) String() string {
|
||||
return fmt.Sprintf("SliceLossIndication %x %x %+v", p.SenderSSRC, p.MediaSSRC, p.SLI)
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (p *SliceLossIndication) DestinationSSRC() []uint32 {
|
||||
return []uint32{p.MediaSSRC}
|
||||
}
|
@@ -332,3 +332,12 @@ func (s *SourceDescriptionItem) Unmarshal(rawPacket []byte) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (s *SourceDescription) DestinationSSRC() []uint32 {
|
||||
out := make([]uint32, len(s.Chunks))
|
||||
for i, v := range s.Chunks {
|
||||
out[i] = v.Source
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
114
pkg/rtcp/transport_layer_nack.go
Normal file
114
pkg/rtcp/transport_layer_nack.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package rtcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// The TransportLayerNack packet informs the encoder about the loss of a transport packet
|
||||
type TransportLayerNack struct {
|
||||
// SSRC of sender
|
||||
SenderSSRC uint32
|
||||
|
||||
// SSRC of the media source
|
||||
MediaSSRC uint32
|
||||
|
||||
Nacks []struct {
|
||||
// ID of lost packets
|
||||
PacketID uint16
|
||||
|
||||
// Bitmask of following lost packets
|
||||
BLP uint16
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
tlnFMT = 1
|
||||
tlnLength = 2
|
||||
nackOffset = 8
|
||||
)
|
||||
|
||||
// Marshal encodes the TransportLayerNack in binary
|
||||
func (p TransportLayerNack) Marshal() ([]byte, error) {
|
||||
|
||||
if len(p.Nacks)+tlnLength > math.MaxUint8 {
|
||||
return nil, errTooManyReports
|
||||
}
|
||||
|
||||
rawPacket := make([]byte, nackOffset+(len(p.Nacks)*4))
|
||||
binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
|
||||
binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
|
||||
for i := 0; i < len(p.Nacks); i++ {
|
||||
binary.BigEndian.PutUint16(rawPacket[nackOffset+(4*i):], p.Nacks[i].PacketID)
|
||||
binary.BigEndian.PutUint16(rawPacket[nackOffset+(4*i)+2:], p.Nacks[i].BLP)
|
||||
}
|
||||
h := p.Header()
|
||||
hData, err := h.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return append(hData, rawPacket...), nil
|
||||
}
|
||||
|
||||
// Unmarshal decodes the TransportLayerNack from binary
|
||||
func (p *TransportLayerNack) Unmarshal(rawPacket []byte) error {
|
||||
var h Header
|
||||
if err := h.Unmarshal(rawPacket); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(rawPacket) < (headerLength + int(4*h.Length)) {
|
||||
return errPacketTooShort
|
||||
}
|
||||
|
||||
if h.Type != TypeTransportSpecificFeedback || h.Count != tlnFMT {
|
||||
return errWrongType
|
||||
}
|
||||
|
||||
p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
|
||||
p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
|
||||
for i := headerLength + nackOffset; i < (headerLength + int(h.Length*4)); i += 4 {
|
||||
p.Nacks = append(p.Nacks, struct {
|
||||
PacketID uint16
|
||||
BLP uint16
|
||||
}{
|
||||
binary.BigEndian.Uint16(rawPacket[i:]),
|
||||
binary.BigEndian.Uint16(rawPacket[i+2:])})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *TransportLayerNack) len() int {
|
||||
return headerLength + nackOffset + (len(p.Nacks) * 4)
|
||||
}
|
||||
|
||||
// Header returns the Header associated with this packet.
|
||||
func (p *TransportLayerNack) Header() Header {
|
||||
return Header{
|
||||
Count: tlnFMT,
|
||||
Type: TypeTransportSpecificFeedback,
|
||||
Length: uint16((p.len() / 4) - 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TransportLayerNack) String() string {
|
||||
o := "Packets Lost:\n"
|
||||
for _, n := range p.Nacks {
|
||||
b := n.BLP
|
||||
o += fmt.Sprintf("\t%d\n", n.PacketID)
|
||||
for i := uint16(0); b != 0; i++ {
|
||||
if (b & (1 << i)) != 0 {
|
||||
b &^= (1 << i)
|
||||
o += fmt.Sprintf("\t%d\n", n.PacketID+i+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (p *TransportLayerNack) DestinationSSRC() []uint32 {
|
||||
return []uint32{p.MediaSSRC}
|
||||
}
|
@@ -2,6 +2,7 @@ package rtp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -47,6 +48,21 @@ const (
|
||||
csrcLength = 4
|
||||
)
|
||||
|
||||
// String helps with debugging by printing packet information in a readable way
|
||||
func (p Packet) String() string {
|
||||
out := "RTP PACKET:\n"
|
||||
|
||||
out += fmt.Sprintf("\tVersion: %v\n", p.Version)
|
||||
out += fmt.Sprintf("\tMarker: %v\n", p.Marker)
|
||||
out += fmt.Sprintf("\tPayload Type: %d\n", p.PayloadType)
|
||||
out += fmt.Sprintf("\tSequence Number: %d\n", p.SequenceNumber)
|
||||
out += fmt.Sprintf("\tTimestamp: %d\n", p.Timestamp)
|
||||
out += fmt.Sprintf("\tSSRC: %d (%x)\n", p.SSRC, p.SSRC)
|
||||
out += fmt.Sprintf("\tPayload Length: %d\n", len(p.Payload))
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Unmarshal parses the passed byte slice and stores the result in the Packet this method is called upon
|
||||
func (p *Packet) Unmarshal(rawPacket []byte) error {
|
||||
if len(rawPacket) < headerLength {
|
||||
|
Reference in New Issue
Block a user