source_description.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. package rtcp
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. )
  6. // SDESType is the item type used in the RTCP SDES control packet.
  7. type SDESType uint8
  8. // RTP SDES item types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-5
  9. const (
  10. SDESEnd SDESType = iota // end of SDES list RFC 3550, 6.5
  11. SDESCNAME // canonical name RFC 3550, 6.5.1
  12. SDESName // user name RFC 3550, 6.5.2
  13. SDESEmail // user's electronic mail address RFC 3550, 6.5.3
  14. SDESPhone // user's phone number RFC 3550, 6.5.4
  15. SDESLocation // geographic user location RFC 3550, 6.5.5
  16. SDESTool // name of application or tool RFC 3550, 6.5.6
  17. SDESNote // notice about the source RFC 3550, 6.5.7
  18. SDESPrivate // private extensions RFC 3550, 6.5.8 (not implemented)
  19. )
  20. func (s SDESType) String() string {
  21. switch s {
  22. case SDESEnd:
  23. return "END"
  24. case SDESCNAME:
  25. return "CNAME"
  26. case SDESName:
  27. return "NAME"
  28. case SDESEmail:
  29. return "EMAIL"
  30. case SDESPhone:
  31. return "PHONE"
  32. case SDESLocation:
  33. return "LOC"
  34. case SDESTool:
  35. return "TOOL"
  36. case SDESNote:
  37. return "NOTE"
  38. case SDESPrivate:
  39. return "PRIV"
  40. default:
  41. return string(s)
  42. }
  43. }
  44. const (
  45. sdesSourceLen = 4
  46. sdesTypeLen = 1
  47. sdesTypeOffset = 0
  48. sdesOctetCountLen = 1
  49. sdesOctetCountOffset = 1
  50. sdesMaxOctetCount = (1 << 8) - 1
  51. sdesTextOffset = 2
  52. )
  53. // A SourceDescription (SDES) packet describes the sources in an RTP stream.
  54. type SourceDescription struct {
  55. Chunks []SourceDescriptionChunk
  56. }
  57. // Marshal encodes the SourceDescription in binary
  58. func (s SourceDescription) Marshal() ([]byte, error) {
  59. /*
  60. * 0 1 2 3
  61. * 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
  62. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  63. * header |V=2|P| SC | PT=SDES=202 | length |
  64. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  65. * chunk | SSRC/CSRC_1 |
  66. * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  67. * | SDES items |
  68. * | ... |
  69. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  70. * chunk | SSRC/CSRC_2 |
  71. * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  72. * | SDES items |
  73. * | ... |
  74. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  75. */
  76. rawPacket := make([]byte, s.len())
  77. packetBody := rawPacket[headerLength:]
  78. chunkOffset := 0
  79. for _, c := range s.Chunks {
  80. data, err := c.Marshal()
  81. if err != nil {
  82. return nil, err
  83. }
  84. copy(packetBody[chunkOffset:], data)
  85. chunkOffset += len(data)
  86. }
  87. if len(s.Chunks) > countMax {
  88. return nil, errTooManyChunks
  89. }
  90. hData, err := s.Header().Marshal()
  91. if err != nil {
  92. return nil, err
  93. }
  94. copy(rawPacket, hData)
  95. return rawPacket, nil
  96. }
  97. // Unmarshal decodes the SourceDescription from binary
  98. func (s *SourceDescription) Unmarshal(rawPacket []byte) error {
  99. /*
  100. * 0 1 2 3
  101. * 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
  102. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  103. * header |V=2|P| SC | PT=SDES=202 | length |
  104. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  105. * chunk | SSRC/CSRC_1 |
  106. * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  107. * | SDES items |
  108. * | ... |
  109. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  110. * chunk | SSRC/CSRC_2 |
  111. * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  112. * | SDES items |
  113. * | ... |
  114. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  115. */
  116. var h Header
  117. if err := h.Unmarshal(rawPacket); err != nil {
  118. return err
  119. }
  120. if h.Type != TypeSourceDescription {
  121. return errWrongType
  122. }
  123. for i := headerLength; i < len(rawPacket); {
  124. var chunk SourceDescriptionChunk
  125. if err := chunk.Unmarshal(rawPacket[i:]); err != nil {
  126. return err
  127. }
  128. s.Chunks = append(s.Chunks, chunk)
  129. i += chunk.len()
  130. }
  131. if len(s.Chunks) != int(h.Count) {
  132. return errInvalidHeader
  133. }
  134. return nil
  135. }
  136. func (s *SourceDescription) len() int {
  137. chunksLength := 0
  138. for _, c := range s.Chunks {
  139. chunksLength += c.len()
  140. }
  141. return headerLength + chunksLength
  142. }
  143. // Header returns the Header associated with this packet.
  144. func (s *SourceDescription) Header() Header {
  145. return Header{
  146. Count: uint8(len(s.Chunks)),
  147. Type: TypeSourceDescription,
  148. Length: uint16((s.len() / 4) - 1),
  149. }
  150. }
  151. // A SourceDescriptionChunk contains items describing a single RTP source
  152. type SourceDescriptionChunk struct {
  153. // The source (ssrc) or contributing source (csrc) identifier this packet describes
  154. Source uint32
  155. Items []SourceDescriptionItem
  156. }
  157. // Marshal encodes the SourceDescriptionChunk in binary
  158. func (s SourceDescriptionChunk) Marshal() ([]byte, error) {
  159. /*
  160. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  161. * | SSRC/CSRC_1 |
  162. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  163. * | SDES items |
  164. * | ... |
  165. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  166. */
  167. rawPacket := make([]byte, sdesSourceLen)
  168. binary.BigEndian.PutUint32(rawPacket, s.Source)
  169. for _, it := range s.Items {
  170. data, err := it.Marshal()
  171. if err != nil {
  172. return nil, err
  173. }
  174. rawPacket = append(rawPacket, data...)
  175. }
  176. // The list of items in each chunk MUST be terminated by one or more null octets
  177. rawPacket = append(rawPacket, uint8(SDESEnd))
  178. // additional null octets MUST be included if needed to pad until the next 32-bit boundary
  179. rawPacket = append(rawPacket, make([]byte, getPadding(len(rawPacket)))...)
  180. return rawPacket, nil
  181. }
  182. // Unmarshal decodes the SourceDescriptionChunk from binary
  183. func (s *SourceDescriptionChunk) Unmarshal(rawPacket []byte) error {
  184. /*
  185. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  186. * | SSRC/CSRC_1 |
  187. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  188. * | SDES items |
  189. * | ... |
  190. * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  191. */
  192. if len(rawPacket) < (sdesSourceLen + sdesTypeLen) {
  193. return errPacketTooShort
  194. }
  195. s.Source = binary.BigEndian.Uint32(rawPacket)
  196. for i := 4; i < len(rawPacket); {
  197. if pktType := SDESType(rawPacket[i]); pktType == SDESEnd {
  198. return nil
  199. }
  200. var it SourceDescriptionItem
  201. if err := it.Unmarshal(rawPacket[i:]); err != nil {
  202. return err
  203. }
  204. s.Items = append(s.Items, it)
  205. i += it.len()
  206. }
  207. return errPacketTooShort
  208. }
  209. func (s SourceDescriptionChunk) len() int {
  210. len := sdesSourceLen
  211. for _, it := range s.Items {
  212. len += it.len()
  213. }
  214. len += sdesTypeLen // for terminating null octet
  215. // align to 32-bit boundary
  216. len += getPadding(len)
  217. return len
  218. }
  219. // A SourceDescriptionItem is a part of a SourceDescription that describes a stream.
  220. type SourceDescriptionItem struct {
  221. // The type identifier for this item. eg, SDESCNAME for canonical name description.
  222. //
  223. // Type zero or SDESEnd is interpreted as the end of an item list and cannot be used.
  224. Type SDESType
  225. // Text is a unicode text blob associated with the item. Its meaning varies based on the item's Type.
  226. Text string
  227. }
  228. func (s SourceDescriptionItem) len() int {
  229. /*
  230. * 0 1 2 3
  231. * 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
  232. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  233. * | CNAME=1 | length | user and domain name ...
  234. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  235. */
  236. return sdesTypeLen + sdesOctetCountLen + len([]byte(s.Text))
  237. }
  238. // Marshal encodes the SourceDescriptionItem in binary
  239. func (s SourceDescriptionItem) Marshal() ([]byte, error) {
  240. /*
  241. * 0 1 2 3
  242. * 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
  243. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  244. * | CNAME=1 | length | user and domain name ...
  245. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  246. */
  247. if s.Type == SDESEnd {
  248. return nil, errSDESMissingType
  249. }
  250. rawPacket := make([]byte, sdesTypeLen+sdesOctetCountLen)
  251. rawPacket[sdesTypeOffset] = uint8(s.Type)
  252. txtBytes := []byte(s.Text)
  253. octetCount := len(txtBytes)
  254. if octetCount > sdesMaxOctetCount {
  255. return nil, errSDESTextTooLong
  256. }
  257. rawPacket[sdesOctetCountOffset] = uint8(octetCount)
  258. rawPacket = append(rawPacket, txtBytes...)
  259. return rawPacket, nil
  260. }
  261. // Unmarshal decodes the SourceDescriptionItem from binary
  262. func (s *SourceDescriptionItem) Unmarshal(rawPacket []byte) error {
  263. /*
  264. * 0 1 2 3
  265. * 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
  266. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  267. * | CNAME=1 | length | user and domain name ...
  268. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  269. */
  270. if len(rawPacket) < (sdesTypeLen + sdesOctetCountLen) {
  271. return errPacketTooShort
  272. }
  273. s.Type = SDESType(rawPacket[sdesTypeOffset])
  274. octetCount := int(rawPacket[sdesOctetCountOffset])
  275. if sdesTextOffset+octetCount > len(rawPacket) {
  276. return errPacketTooShort
  277. }
  278. txtBytes := rawPacket[sdesTextOffset : sdesTextOffset+octetCount]
  279. s.Text = string(txtBytes)
  280. return nil
  281. }
  282. // DestinationSSRC returns an array of SSRC values that this packet refers to.
  283. func (s *SourceDescription) DestinationSSRC() []uint32 {
  284. out := make([]uint32, len(s.Chunks))
  285. for i, v := range s.Chunks {
  286. out[i] = v.Source
  287. }
  288. return out
  289. }
  290. func (s *SourceDescription) String() string {
  291. out := "Source Description:\n"
  292. for _, c := range s.Chunks {
  293. out += fmt.Sprintf("\t%x: %s\n", c.Source, c.Items)
  294. }
  295. return out
  296. }