package rtp
import (
"encoding/binary"
"fmt"
"io"
)
const (
headerExtensionIDReserved = 0xF
)
type HeaderExtension interface {
Set (id uint8 , payload []byte ) error
GetIDs () []uint8
Get (id uint8 ) []byte
Del (id uint8 ) error
Unmarshal (buf []byte ) (int , error )
Marshal () ([]byte , error )
MarshalTo (buf []byte ) (int , error )
MarshalSize () int
}
type OneByteHeaderExtension struct {
payload []byte
}
func (e *OneByteHeaderExtension ) Set (id uint8 , buf []byte ) error {
if id < 1 || id > 14 {
return fmt .Errorf ("%w actual(%d)" , errRFC8285OneByteHeaderIDRange , id )
}
if len (buf ) > 16 {
return fmt .Errorf ("%w actual(%d)" , errRFC8285OneByteHeaderSize , len (buf ))
}
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ] >> 4
payloadLen := int (e .payload [n ]&^0xF0 + 1 )
n ++
if extid == id {
e .payload = append (e .payload [:n +1 ], append (buf , e .payload [n +1 +payloadLen :]...)...)
return nil
}
n += payloadLen
}
e .payload = append (e .payload , (id <<4 | uint8 (len (buf )-1 )))
e .payload = append (e .payload , buf ...)
binary .BigEndian .PutUint16 (e .payload [2 :4 ], binary .BigEndian .Uint16 (e .payload [2 :4 ])+1 )
return nil
}
func (e *OneByteHeaderExtension ) GetIDs () []uint8 {
ids := make ([]uint8 , 0 , binary .BigEndian .Uint16 (e .payload [2 :4 ]))
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ] >> 4
payloadLen := int (e .payload [n ]&^0xF0 + 1 )
n ++
if extid == headerExtensionIDReserved {
break
}
ids = append (ids , extid )
n += payloadLen
}
return ids
}
func (e *OneByteHeaderExtension ) Get (id uint8 ) []byte {
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ] >> 4
payloadLen := int (e .payload [n ]&^0xF0 + 1 )
n ++
if extid == id {
return e .payload [n : n +payloadLen ]
}
n += payloadLen
}
return nil
}
func (e *OneByteHeaderExtension ) Del (id uint8 ) error {
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ] >> 4
payloadLen := int (e .payload [n ]&^0xF0 + 1 )
if extid == id {
e .payload = append (e .payload [:n ], e .payload [n +1 +payloadLen :]...)
return nil
}
n += payloadLen + 1
}
return errHeaderExtensionNotFound
}
func (e *OneByteHeaderExtension ) Unmarshal (buf []byte ) (int , error ) {
profile := binary .BigEndian .Uint16 (buf [0 :2 ])
if profile != ExtensionProfileOneByte {
return 0 , fmt .Errorf ("%w actual(%x)" , errHeaderExtensionNotFound , buf [0 :2 ])
}
e .payload = buf
return len (buf ), nil
}
func (e OneByteHeaderExtension ) Marshal () ([]byte , error ) {
return e .payload , nil
}
func (e OneByteHeaderExtension ) MarshalTo (buf []byte ) (int , error ) {
size := e .MarshalSize ()
if size > len (buf ) {
return 0 , io .ErrShortBuffer
}
return copy (buf , e .payload ), nil
}
func (e OneByteHeaderExtension ) MarshalSize () int {
return len (e .payload )
}
type TwoByteHeaderExtension struct {
payload []byte
}
func (e *TwoByteHeaderExtension ) Set (id uint8 , buf []byte ) error {
if id < 1 {
return fmt .Errorf ("%w actual(%d)" , errRFC8285TwoByteHeaderIDRange , id )
}
if len (buf ) > 255 {
return fmt .Errorf ("%w actual(%d)" , errRFC8285TwoByteHeaderSize , len (buf ))
}
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ]
n ++
payloadLen := int (e .payload [n ])
n ++
if extid == id {
e .payload = append (e .payload [:n +2 ], append (buf , e .payload [n +2 +payloadLen :]...)...)
return nil
}
n += payloadLen
}
e .payload = append (e .payload , id , uint8 (len (buf )))
e .payload = append (e .payload , buf ...)
binary .BigEndian .PutUint16 (e .payload [2 :4 ], binary .BigEndian .Uint16 (e .payload [2 :4 ])+1 )
return nil
}
func (e *TwoByteHeaderExtension ) GetIDs () []uint8 {
ids := make ([]uint8 , 0 , binary .BigEndian .Uint16 (e .payload [2 :4 ]))
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ]
n ++
payloadLen := int (e .payload [n ])
n ++
ids = append (ids , extid )
n += payloadLen
}
return ids
}
func (e *TwoByteHeaderExtension ) Get (id uint8 ) []byte {
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ]
n ++
payloadLen := int (e .payload [n ])
n ++
if extid == id {
return e .payload [n : n +payloadLen ]
}
n += payloadLen
}
return nil
}
func (e *TwoByteHeaderExtension ) Del (id uint8 ) error {
for n := 4 ; n < len (e .payload ); {
if e .payload [n ] == 0x00 {
n ++
continue
}
extid := e .payload [n ]
payloadLen := int (e .payload [n +1 ])
if extid == id {
e .payload = append (e .payload [:n ], e .payload [n +2 +payloadLen :]...)
return nil
}
n += payloadLen + 2
}
return errHeaderExtensionNotFound
}
func (e *TwoByteHeaderExtension ) Unmarshal (buf []byte ) (int , error ) {
profile := binary .BigEndian .Uint16 (buf [0 :2 ])
if profile != ExtensionProfileTwoByte {
return 0 , fmt .Errorf ("%w actual(%x)" , errHeaderExtensionNotFound , buf [0 :2 ])
}
e .payload = buf
return len (buf ), nil
}
func (e TwoByteHeaderExtension ) Marshal () ([]byte , error ) {
return e .payload , nil
}
func (e TwoByteHeaderExtension ) MarshalTo (buf []byte ) (int , error ) {
size := e .MarshalSize ()
if size > len (buf ) {
return 0 , io .ErrShortBuffer
}
return copy (buf , e .payload ), nil
}
func (e TwoByteHeaderExtension ) MarshalSize () int {
return len (e .payload )
}
type RawExtension struct {
payload []byte
}
func (e *RawExtension ) Set (id uint8 , payload []byte ) error {
if id != 0 {
return fmt .Errorf ("%w actual(%d)" , errRFC3550HeaderIDRange , id )
}
e .payload = payload
return nil
}
func (e *RawExtension ) GetIDs () []uint8 {
return []uint8 {0 }
}
func (e *RawExtension ) Get (id uint8 ) []byte {
if id == 0 {
return e .payload
}
return nil
}
func (e *RawExtension ) Del (id uint8 ) error {
if id == 0 {
e .payload = nil
return nil
}
return fmt .Errorf ("%w actual(%d)" , errRFC3550HeaderIDRange , id )
}
func (e *RawExtension ) Unmarshal (buf []byte ) (int , error ) {
profile := binary .BigEndian .Uint16 (buf [0 :2 ])
if profile == ExtensionProfileOneByte || profile == ExtensionProfileTwoByte {
return 0 , fmt .Errorf ("%w actual(%x)" , errHeaderExtensionNotFound , buf [0 :2 ])
}
e .payload = buf
return len (buf ), nil
}
func (e RawExtension ) Marshal () ([]byte , error ) {
return e .payload , nil
}
func (e RawExtension ) MarshalTo (buf []byte ) (int , error ) {
size := e .MarshalSize ()
if size > len (buf ) {
return 0 , io .ErrShortBuffer
}
return copy (buf , e .payload ), nil
}
func (e RawExtension ) MarshalSize () int {
return len (e .payload )
}
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 .