1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
package rtcp
import (
"encoding/binary"
"fmt"
"math"
)
// PacketBitmap shouldn't be used like a normal integral,
// so it's type is masked here. Access it with PacketList().
type PacketBitmap uint16
// NackPair is a wire-representation of a collection of
// Lost RTP packets
type NackPair struct {
// ID of lost packets
PacketID uint16
// Bitmask of following lost packets
LostPackets PacketBitmap
}
// The TransportLayerNack packet informs the encoder about the loss of a transport packet
// IETF RFC 4585, Section 6.2.1
// https://tools.ietf.org/html/rfc4585#section-6.2.1
type TransportLayerNack struct {
// SSRC of sender
SenderSSRC uint32
// SSRC of the media source
MediaSSRC uint32
Nacks []NackPair
}
// NackPairsFromSequenceNumbers generates a slice of NackPair from a list of SequenceNumbers
// This handles generating the proper values for PacketID/LostPackets
func NackPairsFromSequenceNumbers(sequenceNumbers []uint16) (pairs []NackPair) {
if len(sequenceNumbers) == 0 {
return []NackPair{}
}
nackPair := &NackPair{PacketID: sequenceNumbers[0]}
for i := 1; i < len(sequenceNumbers); i++ {
m := sequenceNumbers[i]
if m-nackPair.PacketID > 16 {
pairs = append(pairs, *nackPair)
nackPair = &NackPair{PacketID: m}
continue
}
nackPair.LostPackets |= 1 << (m - nackPair.PacketID - 1)
}
pairs = append(pairs, *nackPair)
return
}
// Range calls f sequentially for each sequence number covered by n.
// If f returns false, Range stops the iteration.
func (n *NackPair) Range(f func(seqno uint16) bool) {
more := f(n.PacketID)
if !more {
return
}
b := n.LostPackets
for i := uint16(0); b != 0; i++ {
if (b & (1 << i)) != 0 {
b &^= (1 << i)
more = f(n.PacketID + i + 1)
if !more {
return
}
}
}
}
// PacketList returns a list of Nack'd packets that's referenced by a NackPair
func (n *NackPair) PacketList() []uint16 {
out := make([]uint16, 0, 17)
n.Range(func(seqno uint16) bool {
out = append(out, seqno)
return true
})
return out
}
const (
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:], uint16(p.Nacks[i].LostPackets))
}
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 {
if len(rawPacket) < (headerLength + ssrcLength) {
return errPacketTooShort
}
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 != FormatTLN {
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, NackPair{
binary.BigEndian.Uint16(rawPacket[i:]),
PacketBitmap(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: FormatTLN,
Type: TypeTransportSpecificFeedback,
Length: uint16((p.len() / 4) - 1),
}
}
func (p TransportLayerNack) String() string {
out := fmt.Sprintf("TransportLayerNack from %x\n", p.SenderSSRC)
out += fmt.Sprintf("\tMedia Ssrc %x\n", p.MediaSSRC)
out += "\tID\tLostPackets\n"
for _, i := range p.Nacks {
out += fmt.Sprintf("\t%d\t%b\n", i.PacketID, i.LostPackets)
}
return out
}
// DestinationSSRC returns an array of SSRC values that this packet refers to.
func (p *TransportLayerNack) DestinationSSRC() []uint32 {
return []uint32{p.MediaSSRC}
}
|