package flexfec
import (
"encoding/binary"
"github.com/pion/interceptor/pkg/flexfec/util"
"github.com/pion/rtp"
)
const (
BaseFec03HeaderSize = 20
)
type FlexEncoder03 struct {
fecBaseSn uint16
payloadType uint8
ssrc uint32
coverage *ProtectionCoverage
}
type FlexEncoder03Factory struct {}
func (f FlexEncoder03Factory ) NewEncoder (payloadType uint8 , ssrc uint32 ) FlexEncoder {
return NewFlexEncoder03 (payloadType , ssrc )
}
func NewFlexEncoder03 (payloadType uint8 , ssrc uint32 ) *FlexEncoder03 {
return &FlexEncoder03 {
payloadType : payloadType ,
ssrc : ssrc ,
fecBaseSn : uint16 (1000 ),
}
}
func (flex *FlexEncoder03 ) EncodeFec (mediaPackets []rtp .Packet , numFecPackets uint32 ) []rtp .Packet {
if len (mediaPackets ) == 0 {
return nil
}
for i := 1 ; i < len (mediaPackets ); i ++ {
if mediaPackets [i ].SequenceNumber != mediaPackets [i -1 ].SequenceNumber +1 {
return nil
}
}
if flex .coverage == nil {
flex .coverage = NewCoverage (mediaPackets , numFecPackets )
} else {
flex .coverage .UpdateCoverage (mediaPackets , numFecPackets )
}
if flex .coverage == nil {
return nil
}
fecPackets := make ([]rtp .Packet , numFecPackets )
for fecPacketIndex := uint32 (0 ); fecPacketIndex < numFecPackets ; fecPacketIndex ++ {
fecPackets [fecPacketIndex ] = flex .encodeFlexFecPacket (fecPacketIndex , mediaPackets [0 ].SequenceNumber )
}
return fecPackets
}
func (flex *FlexEncoder03 ) encodeFlexFecPacket (fecPacketIndex uint32 , mediaBaseSn uint16 ) rtp .Packet {
mediaPacketsIt := flex .coverage .GetCoveredBy (fecPacketIndex )
flexFecHeader := flex .encodeFlexFecHeader (
mediaPacketsIt ,
flex .coverage .ExtractMask1 (fecPacketIndex ),
flex .coverage .ExtractMask2 (fecPacketIndex ),
flex .coverage .ExtractMask3_03 (fecPacketIndex ),
mediaBaseSn ,
)
flexFecRepairPayload := flex .encodeFlexFecRepairPayload (mediaPacketsIt .Reset ())
packet := rtp .Packet {
Header : rtp .Header {
Version : 2 ,
Padding : false ,
Extension : false ,
Marker : false ,
PayloadType : flex .payloadType ,
SequenceNumber : flex .fecBaseSn ,
Timestamp : 54243243 ,
SSRC : flex .ssrc ,
CSRC : []uint32 {},
},
Payload : append (flexFecHeader , flexFecRepairPayload ...),
}
flex .fecBaseSn ++
return packet
}
func (flex *FlexEncoder03 ) encodeFlexFecHeader (
mediaPackets *util .MediaPacketIterator ,
mask1 uint16 ,
optionalMask2 uint32 ,
optionalMask3 uint64 ,
mediaBaseSn uint16 ,
) []byte {
headerSize := BaseFec03HeaderSize
if optionalMask2 > 0 || optionalMask3 > 0 {
headerSize += 4
}
if optionalMask3 > 0 {
headerSize += 8
}
flexFecHeader := make ([]byte , headerSize )
tmpMediaPacketBuf := make ([]byte , 0 )
for mediaPackets .HasNext () {
mediaPacket := mediaPackets .Next ()
if mediaPacket .MarshalSize () > len (tmpMediaPacketBuf ) {
tmpMediaPacketBuf = make ([]byte , mediaPacket .MarshalSize ())
}
n , err := mediaPacket .MarshalTo (tmpMediaPacketBuf )
if n == 0 || err != nil {
return nil
}
flexFecHeader [0 ] ^= tmpMediaPacketBuf [0 ]
flexFecHeader [1 ] ^= tmpMediaPacketBuf [1 ]
flexFecHeader [0 ] &= 0b00111111
lengthRecoveryVal := uint16 (mediaPacket .MarshalSize () - BaseRTPHeaderSize )
flexFecHeader [2 ] ^= uint8 (lengthRecoveryVal >> 8 )
flexFecHeader [3 ] ^= uint8 (lengthRecoveryVal )
flexFecHeader [4 ] ^= tmpMediaPacketBuf [4 ]
flexFecHeader [5 ] ^= tmpMediaPacketBuf [5 ]
flexFecHeader [6 ] ^= tmpMediaPacketBuf [6 ]
flexFecHeader [7 ] ^= tmpMediaPacketBuf [7 ]
}
flexFecHeader [8 ] = 1
flexFecHeader [9 ] = 0
flexFecHeader [10 ] = 0
flexFecHeader [11 ] = 0
binary .BigEndian .PutUint32 (flexFecHeader [12 :16 ], mediaPackets .First ().SSRC )
binary .BigEndian .PutUint16 (flexFecHeader [16 :18 ], mediaBaseSn )
binary .BigEndian .PutUint16 (flexFecHeader [18 :20 ], mask1 )
if optionalMask2 == 0 && optionalMask3 == 0 {
flexFecHeader [18 ] |= 0b10000000
return flexFecHeader
}
binary .BigEndian .PutUint32 (flexFecHeader [20 :24 ], optionalMask2 )
if optionalMask3 == 0 {
flexFecHeader [20 ] |= 0b10000000
} else {
binary .BigEndian .PutUint64 (flexFecHeader [24 :32 ], optionalMask3 )
flexFecHeader [24 ] |= 0b10000000
}
return flexFecHeader
}
func (flex *FlexEncoder03 ) encodeFlexFecRepairPayload (mediaPackets *util .MediaPacketIterator ) []byte {
flexFecPayload := make ([]byte , mediaPackets .First ().MarshalSize ()-BaseRTPHeaderSize )
tmpMediaPacketBuf := make ([]byte , 0 )
for mediaPackets .HasNext () {
mediaPacket := mediaPackets .Next ()
if mediaPacket .MarshalSize () > len (tmpMediaPacketBuf ) {
tmpMediaPacketBuf = make ([]byte , mediaPacket .MarshalSize ())
}
n , err := mediaPacket .MarshalTo (tmpMediaPacketBuf )
if n == 0 || err != nil {
return nil
}
if len (flexFecPayload ) < mediaPacket .MarshalSize ()-BaseRTPHeaderSize {
flexFecPayloadTmp := make ([]byte , mediaPacket .MarshalSize ()-BaseRTPHeaderSize )
copy (flexFecPayloadTmp , flexFecPayload )
flexFecPayload = flexFecPayloadTmp
}
for byteIndex := 0 ; byteIndex < mediaPacket .MarshalSize ()-BaseRTPHeaderSize ; byteIndex ++ {
flexFecPayload [byteIndex ] ^= tmpMediaPacketBuf [byteIndex +BaseRTPHeaderSize ]
}
}
return flexFecPayload
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .