slice_loss_indication.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package rtcp
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "math"
  6. )
  7. // SLIEntry represents a single entry to the SLI packet's
  8. // list of lost slices.
  9. type SLIEntry struct {
  10. // ID of first lost slice
  11. First uint16
  12. // Number of lost slices
  13. Number uint16
  14. // ID of related picture
  15. Picture uint8
  16. }
  17. // The SliceLossIndication packet informs the encoder about the loss of a picture slice
  18. type SliceLossIndication struct {
  19. // SSRC of sender
  20. SenderSSRC uint32
  21. // SSRC of the media source
  22. MediaSSRC uint32
  23. SLI []SLIEntry
  24. }
  25. const (
  26. sliLength = 2
  27. sliOffset = 8
  28. )
  29. // Marshal encodes the SliceLossIndication in binary
  30. func (p SliceLossIndication) Marshal() ([]byte, error) {
  31. if len(p.SLI)+sliLength > math.MaxUint8 {
  32. return nil, errTooManyReports
  33. }
  34. rawPacket := make([]byte, sliOffset+(len(p.SLI)*4))
  35. binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
  36. binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
  37. for i, s := range p.SLI {
  38. sli := ((uint32(s.First) & 0x1FFF) << 19) |
  39. ((uint32(s.Number) & 0x1FFF) << 6) |
  40. (uint32(s.Picture) & 0x3F)
  41. binary.BigEndian.PutUint32(rawPacket[sliOffset+(4*i):], sli)
  42. }
  43. hData, err := p.Header().Marshal()
  44. if err != nil {
  45. return nil, err
  46. }
  47. return append(hData, rawPacket...), nil
  48. }
  49. // Unmarshal decodes the SliceLossIndication from binary
  50. func (p *SliceLossIndication) Unmarshal(rawPacket []byte) error {
  51. if len(rawPacket) < (headerLength + ssrcLength) {
  52. return errPacketTooShort
  53. }
  54. var h Header
  55. if err := h.Unmarshal(rawPacket); err != nil {
  56. return err
  57. }
  58. if len(rawPacket) < (headerLength + int(4*h.Length)) {
  59. return errPacketTooShort
  60. }
  61. if h.Type != TypeTransportSpecificFeedback || h.Count != FormatSLI {
  62. return errWrongType
  63. }
  64. p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
  65. p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
  66. for i := headerLength + sliOffset; i < (headerLength + int(h.Length*4)); i += 4 {
  67. sli := binary.BigEndian.Uint32(rawPacket[i:])
  68. p.SLI = append(p.SLI, SLIEntry{
  69. First: uint16((sli >> 19) & 0x1FFF),
  70. Number: uint16((sli >> 6) & 0x1FFF),
  71. Picture: uint8(sli & 0x3F),
  72. })
  73. }
  74. return nil
  75. }
  76. func (p *SliceLossIndication) len() int {
  77. return headerLength + sliOffset + (len(p.SLI) * 4)
  78. }
  79. // Header returns the Header associated with this packet.
  80. func (p *SliceLossIndication) Header() Header {
  81. return Header{
  82. Count: FormatSLI,
  83. Type: TypeTransportSpecificFeedback,
  84. Length: uint16((p.len() / 4) - 1),
  85. }
  86. }
  87. func (p *SliceLossIndication) String() string {
  88. return fmt.Sprintf("SliceLossIndication %x %x %+v", p.SenderSSRC, p.MediaSSRC, p.SLI)
  89. }
  90. // DestinationSSRC returns an array of SSRC values that this packet refers to.
  91. func (p *SliceLossIndication) DestinationSSRC() []uint32 {
  92. return []uint32{p.MediaSSRC}
  93. }