transport_layer_cc.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. package rtcp
  2. // Author: adwpc
  3. import (
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "math"
  8. )
  9. // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
  10. // 0 1 2 3
  11. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  12. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  13. // |V=2|P| FMT=15 | PT=205 | length |
  14. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  15. // | SSRC of packet sender |
  16. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  17. // | SSRC of media source |
  18. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  19. // | base sequence number | packet status count |
  20. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  21. // | reference time | fb pkt. count |
  22. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  23. // | packet chunk | packet chunk |
  24. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  25. // . .
  26. // . .
  27. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  28. // | packet chunk | recv delta | recv delta |
  29. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  30. // . .
  31. // . .
  32. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  33. // | recv delta | recv delta | zero padding |
  34. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  35. // for packet status chunk
  36. const (
  37. // type of packet status chunk
  38. TypeTCCRunLengthChunk = 0
  39. TypeTCCStatusVectorChunk = 1
  40. // len of packet status chunk
  41. packetStatusChunkLength = 2
  42. )
  43. // type of packet status symbol and recv delta
  44. const (
  45. // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.1
  46. TypeTCCPacketNotReceived = uint16(iota)
  47. TypeTCCPacketReceivedSmallDelta
  48. TypeTCCPacketReceivedLargeDelta
  49. // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-7
  50. // see Example 2: "packet received, w/o recv delta"
  51. TypeTCCPacketReceivedWithoutDelta
  52. )
  53. // for status vector chunk
  54. const (
  55. // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.4
  56. TypeTCCSymbolSizeOneBit = 0
  57. TypeTCCSymbolSizeTwoBit = 1
  58. // Notice: RFC is wrong: "packet received" (0) and "packet not received" (1)
  59. // if S == TypeTCCSymbolSizeOneBit, symbol list will be: TypeTCCPacketNotReceived TypeTCCPacketReceivedSmallDelta
  60. // if S == TypeTCCSymbolSizeTwoBit, symbol list will be same as above:
  61. )
  62. func numOfBitsOfSymbolSize() map[uint16]uint16 {
  63. return map[uint16]uint16{
  64. TypeTCCSymbolSizeOneBit: 1,
  65. TypeTCCSymbolSizeTwoBit: 2,
  66. }
  67. }
  68. var (
  69. errPacketStatusChunkLength = errors.New("packet status chunk must be 2 bytes")
  70. errDeltaExceedLimit = errors.New("delta exceed limit")
  71. )
  72. // PacketStatusChunk has two kinds:
  73. // RunLengthChunk and StatusVectorChunk
  74. type PacketStatusChunk interface {
  75. Marshal() ([]byte, error)
  76. Unmarshal(rawPacket []byte) error
  77. }
  78. // RunLengthChunk T=TypeTCCRunLengthChunk
  79. // 0 1
  80. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  81. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  82. // |T| S | Run Length |
  83. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  84. type RunLengthChunk struct {
  85. PacketStatusChunk
  86. // T = TypeTCCRunLengthChunk
  87. Type uint16
  88. // S: type of packet status
  89. // kind: TypeTCCPacketNotReceived or...
  90. PacketStatusSymbol uint16
  91. // RunLength: count of S
  92. RunLength uint16
  93. }
  94. // Marshal ..
  95. func (r RunLengthChunk) Marshal() ([]byte, error) {
  96. chunk := make([]byte, 2)
  97. // append 1 bit '0'
  98. dst, err := setNBitsOfUint16(0, 1, 0, 0)
  99. if err != nil {
  100. return nil, err
  101. }
  102. // append 2 bit PacketStatusSymbol
  103. dst, err = setNBitsOfUint16(dst, 2, 1, r.PacketStatusSymbol)
  104. if err != nil {
  105. return nil, err
  106. }
  107. // append 13 bit RunLength
  108. dst, err = setNBitsOfUint16(dst, 13, 3, r.RunLength)
  109. if err != nil {
  110. return nil, err
  111. }
  112. binary.BigEndian.PutUint16(chunk, dst)
  113. return chunk, nil
  114. }
  115. // Unmarshal ..
  116. func (r *RunLengthChunk) Unmarshal(rawPacket []byte) error {
  117. if len(rawPacket) != packetStatusChunkLength {
  118. return errPacketStatusChunkLength
  119. }
  120. // record type
  121. r.Type = TypeTCCRunLengthChunk
  122. // get PacketStatusSymbol
  123. // r.PacketStatusSymbol = uint16(rawPacket[0] >> 5 & 0x03)
  124. r.PacketStatusSymbol = getNBitsFromByte(rawPacket[0], 1, 2)
  125. // get RunLength
  126. // r.RunLength = uint16(rawPacket[0]&0x1F)*256 + uint16(rawPacket[1])
  127. r.RunLength = getNBitsFromByte(rawPacket[0], 3, 5)<<8 + uint16(rawPacket[1])
  128. return nil
  129. }
  130. // StatusVectorChunk T=typeStatusVecotrChunk
  131. // 0 1
  132. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  133. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  134. // |T|S| symbol list |
  135. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  136. type StatusVectorChunk struct {
  137. PacketStatusChunk
  138. // T = TypeTCCRunLengthChunk
  139. Type uint16
  140. // TypeTCCSymbolSizeOneBit or TypeTCCSymbolSizeTwoBit
  141. SymbolSize uint16
  142. // when SymbolSize = TypeTCCSymbolSizeOneBit, SymbolList is 14*1bit:
  143. // TypeTCCSymbolListPacketReceived or TypeTCCSymbolListPacketNotReceived
  144. // when SymbolSize = TypeTCCSymbolSizeTwoBit, SymbolList is 7*2bit:
  145. // TypeTCCPacketNotReceived TypeTCCPacketReceivedSmallDelta TypeTCCPacketReceivedLargeDelta or typePacketReserved
  146. SymbolList []uint16
  147. }
  148. // Marshal ..
  149. func (r StatusVectorChunk) Marshal() ([]byte, error) {
  150. chunk := make([]byte, 2)
  151. // set first bit '1'
  152. dst, err := setNBitsOfUint16(0, 1, 0, 1)
  153. if err != nil {
  154. return nil, err
  155. }
  156. // set second bit SymbolSize
  157. dst, err = setNBitsOfUint16(dst, 1, 1, r.SymbolSize)
  158. if err != nil {
  159. return nil, err
  160. }
  161. numOfBits := numOfBitsOfSymbolSize()[r.SymbolSize]
  162. // append 14 bit SymbolList
  163. for i, s := range r.SymbolList {
  164. index := numOfBits*uint16(i) + 2
  165. dst, err = setNBitsOfUint16(dst, numOfBits, index, s)
  166. if err != nil {
  167. return nil, err
  168. }
  169. }
  170. binary.BigEndian.PutUint16(chunk, dst)
  171. // set SymbolList(bit8-15)
  172. // chunk[1] = uint8(r.SymbolList) & 0x0f
  173. return chunk, nil
  174. }
  175. // Unmarshal ..
  176. func (r *StatusVectorChunk) Unmarshal(rawPacket []byte) error {
  177. if len(rawPacket) != packetStatusChunkLength {
  178. return errPacketStatusChunkLength
  179. }
  180. r.Type = TypeTCCStatusVectorChunk
  181. r.SymbolSize = getNBitsFromByte(rawPacket[0], 1, 1)
  182. if r.SymbolSize == TypeTCCSymbolSizeOneBit {
  183. for i := uint16(0); i < 6; i++ {
  184. r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[0], 2+i, 1))
  185. }
  186. for i := uint16(0); i < 8; i++ {
  187. r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[1], i, 1))
  188. }
  189. return nil
  190. }
  191. if r.SymbolSize == TypeTCCSymbolSizeTwoBit {
  192. for i := uint16(0); i < 3; i++ {
  193. r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[0], 2+i*2, 2))
  194. }
  195. for i := uint16(0); i < 4; i++ {
  196. r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[1], i*2, 2))
  197. }
  198. return nil
  199. }
  200. r.SymbolSize = getNBitsFromByte(rawPacket[0], 2, 6)<<8 + uint16(rawPacket[1])
  201. return nil
  202. }
  203. const (
  204. // TypeTCCDeltaScaleFactor https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.5
  205. TypeTCCDeltaScaleFactor = 250
  206. )
  207. // RecvDelta are represented as multiples of 250us
  208. // small delta is 1 byte: [0,63.75]ms = [0, 63750]us = [0, 255]*250us
  209. // big delta is 2 bytes: [-8192.0, 8191.75]ms = [-8192000, 8191750]us = [-32768, 32767]*250us
  210. // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.5
  211. type RecvDelta struct {
  212. Type uint16
  213. // us
  214. Delta int64
  215. }
  216. // Marshal ..
  217. func (r RecvDelta) Marshal() ([]byte, error) {
  218. delta := r.Delta / TypeTCCDeltaScaleFactor
  219. // small delta
  220. if r.Type == TypeTCCPacketReceivedSmallDelta && delta >= 0 && delta <= math.MaxUint8 {
  221. deltaChunk := make([]byte, 1)
  222. deltaChunk[0] = byte(delta)
  223. return deltaChunk, nil
  224. }
  225. // big delta
  226. if r.Type == TypeTCCPacketReceivedLargeDelta && delta >= math.MinInt16 && delta <= math.MaxInt16 {
  227. deltaChunk := make([]byte, 2)
  228. binary.BigEndian.PutUint16(deltaChunk, uint16(delta))
  229. return deltaChunk, nil
  230. }
  231. // overflow
  232. return nil, errDeltaExceedLimit
  233. }
  234. // Unmarshal ..
  235. func (r *RecvDelta) Unmarshal(rawPacket []byte) error {
  236. chunkLen := len(rawPacket)
  237. // must be 1 or 2 bytes
  238. if chunkLen != 1 && chunkLen != 2 {
  239. return errDeltaExceedLimit
  240. }
  241. if chunkLen == 1 {
  242. r.Type = TypeTCCPacketReceivedSmallDelta
  243. r.Delta = TypeTCCDeltaScaleFactor * int64(rawPacket[0])
  244. return nil
  245. }
  246. r.Type = TypeTCCPacketReceivedLargeDelta
  247. r.Delta = TypeTCCDeltaScaleFactor * int64(int16(binary.BigEndian.Uint16(rawPacket)))
  248. return nil
  249. }
  250. const (
  251. // the offset after header
  252. baseSequenceNumberOffset = 8
  253. packetStatusCountOffset = 10
  254. referenceTimeOffset = 12
  255. fbPktCountOffset = 15
  256. packetChunkOffset = 16
  257. )
  258. // TransportLayerCC for sender-BWE
  259. // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
  260. type TransportLayerCC struct {
  261. // header
  262. Header Header
  263. // SSRC of sender
  264. SenderSSRC uint32
  265. // SSRC of the media source
  266. MediaSSRC uint32
  267. // Transport wide sequence of rtp extension
  268. BaseSequenceNumber uint16
  269. // PacketStatusCount
  270. PacketStatusCount uint16
  271. // ReferenceTime
  272. ReferenceTime uint32
  273. // FbPktCount
  274. FbPktCount uint8
  275. // PacketChunks
  276. PacketChunks []PacketStatusChunk
  277. // RecvDeltas
  278. RecvDeltas []*RecvDelta
  279. }
  280. // Header returns the Header associated with this packet.
  281. // func (t *TransportLayerCC) Header() Header {
  282. // return t.Header
  283. // return Header{
  284. // Padding: true,
  285. // Count: FormatTCC,
  286. // Type: TypeTCCTransportSpecificFeedback,
  287. // // https://tools.ietf.org/html/rfc4585#page-33
  288. // Length: uint16((t.len() / 4) - 1),
  289. // }
  290. // }
  291. func (t *TransportLayerCC) packetLen() uint16 {
  292. n := uint16(headerLength + packetChunkOffset + len(t.PacketChunks)*2)
  293. for _, d := range t.RecvDeltas {
  294. if d.Type == TypeTCCPacketReceivedSmallDelta {
  295. n++
  296. } else {
  297. n += 2
  298. }
  299. }
  300. return n
  301. }
  302. // Len return total bytes with padding
  303. func (t *TransportLayerCC) Len() uint16 {
  304. n := t.packetLen()
  305. // has padding
  306. if n%4 != 0 {
  307. n = (n/4 + 1) * 4
  308. }
  309. return n
  310. }
  311. func (t TransportLayerCC) String() string {
  312. out := fmt.Sprintf("TransportLayerCC:\n\tHeader %v\n", t.Header)
  313. out += fmt.Sprintf("TransportLayerCC:\n\tSender Ssrc %d\n", t.SenderSSRC)
  314. out += fmt.Sprintf("\tMedia Ssrc %d\n", t.MediaSSRC)
  315. out += fmt.Sprintf("\tBase Sequence Number %d\n", t.BaseSequenceNumber)
  316. out += fmt.Sprintf("\tStatus Count %d\n", t.PacketStatusCount)
  317. out += fmt.Sprintf("\tReference Time %d\n", t.ReferenceTime)
  318. out += fmt.Sprintf("\tFeedback Packet Count %d\n", t.FbPktCount)
  319. out += "\tPacketChunks "
  320. for _, chunk := range t.PacketChunks {
  321. out += fmt.Sprintf("%+v ", chunk)
  322. }
  323. out += "\n\tRecvDeltas "
  324. for _, delta := range t.RecvDeltas {
  325. out += fmt.Sprintf("%+v ", delta)
  326. }
  327. out += "\n"
  328. return out
  329. }
  330. // Marshal encodes the TransportLayerCC in binary
  331. func (t TransportLayerCC) Marshal() ([]byte, error) {
  332. header, err := t.Header.Marshal()
  333. if err != nil {
  334. return nil, err
  335. }
  336. payload := make([]byte, t.Len()-headerLength)
  337. binary.BigEndian.PutUint32(payload, t.SenderSSRC)
  338. binary.BigEndian.PutUint32(payload[4:], t.MediaSSRC)
  339. binary.BigEndian.PutUint16(payload[baseSequenceNumberOffset:], t.BaseSequenceNumber)
  340. binary.BigEndian.PutUint16(payload[packetStatusCountOffset:], t.PacketStatusCount)
  341. ReferenceTimeAndFbPktCount := appendNBitsToUint32(0, 24, t.ReferenceTime)
  342. ReferenceTimeAndFbPktCount = appendNBitsToUint32(ReferenceTimeAndFbPktCount, 8, uint32(t.FbPktCount))
  343. binary.BigEndian.PutUint32(payload[referenceTimeOffset:], ReferenceTimeAndFbPktCount)
  344. for i, chunk := range t.PacketChunks {
  345. b, err := chunk.Marshal()
  346. if err != nil {
  347. return nil, err
  348. }
  349. copy(payload[packetChunkOffset+i*2:], b)
  350. }
  351. recvDeltaOffset := packetChunkOffset + len(t.PacketChunks)*2
  352. var i int
  353. for _, delta := range t.RecvDeltas {
  354. b, err := delta.Marshal()
  355. if err == nil {
  356. copy(payload[recvDeltaOffset+i:], b)
  357. i++
  358. if delta.Type == TypeTCCPacketReceivedLargeDelta {
  359. i++
  360. }
  361. }
  362. }
  363. if t.Header.Padding {
  364. payload[len(payload)-1] = uint8(t.Len() - t.packetLen())
  365. }
  366. return append(header, payload...), nil
  367. }
  368. // Unmarshal ..
  369. func (t *TransportLayerCC) Unmarshal(rawPacket []byte) error { //nolint:gocognit
  370. if len(rawPacket) < (headerLength + ssrcLength) {
  371. return errPacketTooShort
  372. }
  373. if err := t.Header.Unmarshal(rawPacket); err != nil {
  374. return err
  375. }
  376. // https://tools.ietf.org/html/rfc4585#page-33
  377. // header's length + payload's length
  378. totalLength := 4 * (t.Header.Length + 1)
  379. if totalLength < headerLength+packetChunkOffset {
  380. return errPacketTooShort
  381. }
  382. if len(rawPacket) < int(totalLength) {
  383. return errPacketTooShort
  384. }
  385. if t.Header.Type != TypeTransportSpecificFeedback || t.Header.Count != FormatTCC {
  386. return errWrongType
  387. }
  388. t.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
  389. t.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
  390. t.BaseSequenceNumber = binary.BigEndian.Uint16(rawPacket[headerLength+baseSequenceNumberOffset:])
  391. t.PacketStatusCount = binary.BigEndian.Uint16(rawPacket[headerLength+packetStatusCountOffset:])
  392. t.ReferenceTime = get24BitsFromBytes(rawPacket[headerLength+referenceTimeOffset : headerLength+referenceTimeOffset+3])
  393. t.FbPktCount = rawPacket[headerLength+fbPktCountOffset]
  394. packetStatusPos := uint16(headerLength + packetChunkOffset)
  395. var processedPacketNum uint16
  396. for processedPacketNum < t.PacketStatusCount {
  397. if packetStatusPos+packetStatusChunkLength >= totalLength {
  398. return errPacketTooShort
  399. }
  400. typ := getNBitsFromByte(rawPacket[packetStatusPos : packetStatusPos+1][0], 0, 1)
  401. var iPacketStatus PacketStatusChunk
  402. switch typ {
  403. case TypeTCCRunLengthChunk:
  404. packetStatus := &RunLengthChunk{Type: typ}
  405. iPacketStatus = packetStatus
  406. err := packetStatus.Unmarshal(rawPacket[packetStatusPos : packetStatusPos+2])
  407. if err != nil {
  408. return err
  409. }
  410. packetNumberToProcess := min(t.PacketStatusCount-processedPacketNum, packetStatus.RunLength)
  411. if packetStatus.PacketStatusSymbol == TypeTCCPacketReceivedSmallDelta ||
  412. packetStatus.PacketStatusSymbol == TypeTCCPacketReceivedLargeDelta {
  413. for j := uint16(0); j < packetNumberToProcess; j++ {
  414. t.RecvDeltas = append(t.RecvDeltas, &RecvDelta{Type: packetStatus.PacketStatusSymbol})
  415. }
  416. }
  417. processedPacketNum += packetNumberToProcess
  418. case TypeTCCStatusVectorChunk:
  419. packetStatus := &StatusVectorChunk{Type: typ}
  420. iPacketStatus = packetStatus
  421. err := packetStatus.Unmarshal(rawPacket[packetStatusPos : packetStatusPos+2])
  422. if err != nil {
  423. return err
  424. }
  425. if packetStatus.SymbolSize == TypeTCCSymbolSizeOneBit {
  426. for j := 0; j < len(packetStatus.SymbolList); j++ {
  427. if packetStatus.SymbolList[j] == TypeTCCPacketReceivedSmallDelta {
  428. t.RecvDeltas = append(t.RecvDeltas, &RecvDelta{Type: TypeTCCPacketReceivedSmallDelta})
  429. }
  430. }
  431. }
  432. if packetStatus.SymbolSize == TypeTCCSymbolSizeTwoBit {
  433. for j := 0; j < len(packetStatus.SymbolList); j++ {
  434. if packetStatus.SymbolList[j] == TypeTCCPacketReceivedSmallDelta || packetStatus.SymbolList[j] == TypeTCCPacketReceivedLargeDelta {
  435. t.RecvDeltas = append(t.RecvDeltas, &RecvDelta{Type: packetStatus.SymbolList[j]})
  436. }
  437. }
  438. }
  439. processedPacketNum += uint16(len(packetStatus.SymbolList))
  440. }
  441. packetStatusPos += packetStatusChunkLength
  442. t.PacketChunks = append(t.PacketChunks, iPacketStatus)
  443. }
  444. recvDeltasPos := packetStatusPos
  445. for _, delta := range t.RecvDeltas {
  446. if recvDeltasPos >= totalLength {
  447. return errPacketTooShort
  448. }
  449. if delta.Type == TypeTCCPacketReceivedSmallDelta {
  450. err := delta.Unmarshal(rawPacket[recvDeltasPos : recvDeltasPos+1])
  451. if err != nil {
  452. return err
  453. }
  454. recvDeltasPos++
  455. }
  456. if delta.Type == TypeTCCPacketReceivedLargeDelta {
  457. err := delta.Unmarshal(rawPacket[recvDeltasPos : recvDeltasPos+2])
  458. if err != nil {
  459. return err
  460. }
  461. recvDeltasPos += 2
  462. }
  463. }
  464. return nil
  465. }
  466. // DestinationSSRC returns an array of SSRC values that this packet refers to.
  467. func (t TransportLayerCC) DestinationSSRC() []uint32 {
  468. return []uint32{t.MediaSSRC}
  469. }
  470. func min(x, y uint16) uint16 {
  471. if x < y {
  472. return x
  473. }
  474. return y
  475. }