marshal.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package sdp
  4. // Marshal takes a SDP struct to text
  5. // https://tools.ietf.org/html/rfc4566#section-5
  6. // Session description
  7. //
  8. // v= (protocol version)
  9. // o= (originator and session identifier)
  10. // s= (session name)
  11. // i=* (session information)
  12. // u=* (URI of description)
  13. // e=* (email address)
  14. // p=* (phone number)
  15. // c=* (connection information -- not required if included in
  16. // all media)
  17. // b=* (zero or more bandwidth information lines)
  18. // One or more time descriptions ("t=" and "r=" lines; see below)
  19. // z=* (time zone adjustments)
  20. // k=* (encryption key)
  21. // a=* (zero or more session attribute lines)
  22. // Zero or more media descriptions
  23. //
  24. // Time description
  25. //
  26. // t= (time the session is active)
  27. // r=* (zero or more repeat times)
  28. //
  29. // Media description, if present
  30. //
  31. // m= (media name and transport address)
  32. // i=* (media title)
  33. // c=* (connection information -- optional if included at
  34. // session level)
  35. // b=* (zero or more bandwidth information lines)
  36. // k=* (encryption key)
  37. // a=* (zero or more media attribute lines)
  38. func (s *SessionDescription) Marshal() ([]byte, error) {
  39. m := make(marshaller, 0, s.MarshalSize())
  40. m.addKeyValue("v=", s.Version.marshalInto)
  41. m.addKeyValue("o=", s.Origin.marshalInto)
  42. m.addKeyValue("s=", s.SessionName.marshalInto)
  43. if s.SessionInformation != nil {
  44. m.addKeyValue("i=", s.SessionInformation.marshalInto)
  45. }
  46. if s.URI != nil {
  47. m = append(m, "u="...)
  48. m = append(m, s.URI.String()...)
  49. m = append(m, "\r\n"...)
  50. }
  51. if s.EmailAddress != nil {
  52. m.addKeyValue("e=", s.EmailAddress.marshalInto)
  53. }
  54. if s.PhoneNumber != nil {
  55. m.addKeyValue("p=", s.PhoneNumber.marshalInto)
  56. }
  57. if s.ConnectionInformation != nil {
  58. m.addKeyValue("c=", s.ConnectionInformation.marshalInto)
  59. }
  60. for _, b := range s.Bandwidth {
  61. m.addKeyValue("b=", b.marshalInto)
  62. }
  63. for _, td := range s.TimeDescriptions {
  64. m.addKeyValue("t=", td.Timing.marshalInto)
  65. for _, r := range td.RepeatTimes {
  66. m.addKeyValue("r=", r.marshalInto)
  67. }
  68. }
  69. if len(s.TimeZones) > 0 {
  70. m = append(m, "z="...)
  71. for i, z := range s.TimeZones {
  72. if i > 0 {
  73. m = append(m, ' ')
  74. }
  75. m = z.marshalInto(m)
  76. }
  77. m = append(m, "\r\n"...)
  78. }
  79. if s.EncryptionKey != nil {
  80. m.addKeyValue("k=", s.EncryptionKey.marshalInto)
  81. }
  82. for _, a := range s.Attributes {
  83. m.addKeyValue("a=", a.marshalInto)
  84. }
  85. for _, md := range s.MediaDescriptions {
  86. m.addKeyValue("m=", md.MediaName.marshalInto)
  87. if md.MediaTitle != nil {
  88. m.addKeyValue("i=", md.MediaTitle.marshalInto)
  89. }
  90. if md.ConnectionInformation != nil {
  91. m.addKeyValue("c=", md.ConnectionInformation.marshalInto)
  92. }
  93. for _, b := range md.Bandwidth {
  94. m.addKeyValue("b=", b.marshalInto)
  95. }
  96. if md.EncryptionKey != nil {
  97. m.addKeyValue("k=", md.EncryptionKey.marshalInto)
  98. }
  99. for _, a := range md.Attributes {
  100. m.addKeyValue("a=", a.marshalInto)
  101. }
  102. }
  103. return m, nil
  104. }
  105. // `$type=` and CRLF size
  106. const lineBaseSize = 4
  107. // MarshalSize returns the size of the SessionDescription once marshaled.
  108. func (s *SessionDescription) MarshalSize() (marshalSize int) {
  109. marshalSize += lineBaseSize + s.Version.marshalSize()
  110. marshalSize += lineBaseSize + s.Origin.marshalSize()
  111. marshalSize += lineBaseSize + s.SessionName.marshalSize()
  112. if s.SessionInformation != nil {
  113. marshalSize += lineBaseSize + s.SessionInformation.marshalSize()
  114. }
  115. if s.URI != nil {
  116. marshalSize += lineBaseSize + len(s.URI.String())
  117. }
  118. if s.EmailAddress != nil {
  119. marshalSize += lineBaseSize + s.EmailAddress.marshalSize()
  120. }
  121. if s.PhoneNumber != nil {
  122. marshalSize += lineBaseSize + s.PhoneNumber.marshalSize()
  123. }
  124. if s.ConnectionInformation != nil {
  125. marshalSize += lineBaseSize + s.ConnectionInformation.marshalSize()
  126. }
  127. for _, b := range s.Bandwidth {
  128. marshalSize += lineBaseSize + b.marshalSize()
  129. }
  130. for _, td := range s.TimeDescriptions {
  131. marshalSize += lineBaseSize + td.Timing.marshalSize()
  132. for _, r := range td.RepeatTimes {
  133. marshalSize += lineBaseSize + r.marshalSize()
  134. }
  135. }
  136. if len(s.TimeZones) > 0 {
  137. marshalSize += lineBaseSize
  138. for i, z := range s.TimeZones {
  139. if i > 0 {
  140. marshalSize++
  141. }
  142. marshalSize += z.marshalSize()
  143. }
  144. }
  145. if s.EncryptionKey != nil {
  146. marshalSize += lineBaseSize + s.EncryptionKey.marshalSize()
  147. }
  148. for _, a := range s.Attributes {
  149. marshalSize += lineBaseSize + a.marshalSize()
  150. }
  151. for _, md := range s.MediaDescriptions {
  152. marshalSize += lineBaseSize + md.MediaName.marshalSize()
  153. if md.MediaTitle != nil {
  154. marshalSize += lineBaseSize + md.MediaTitle.marshalSize()
  155. }
  156. if md.ConnectionInformation != nil {
  157. marshalSize += lineBaseSize + md.ConnectionInformation.marshalSize()
  158. }
  159. for _, b := range md.Bandwidth {
  160. marshalSize += lineBaseSize + b.marshalSize()
  161. }
  162. if md.EncryptionKey != nil {
  163. marshalSize += lineBaseSize + md.EncryptionKey.marshalSize()
  164. }
  165. for _, a := range md.Attributes {
  166. marshalSize += lineBaseSize + a.marshalSize()
  167. }
  168. }
  169. return marshalSize
  170. }
  171. // marshaller contains state during marshaling.
  172. type marshaller []byte
  173. func (m *marshaller) addKeyValue(key string, value func([]byte) []byte) {
  174. *m = append(*m, key...)
  175. *m = value(*m)
  176. *m = append(*m, "\r\n"...)
  177. }
  178. func lenUint(i uint64) (count int) {
  179. if i == 0 {
  180. return 1
  181. }
  182. for i != 0 {
  183. i /= 10
  184. count++
  185. }
  186. return
  187. }
  188. func lenInt(i int64) (count int) {
  189. if i < 0 {
  190. return lenUint(uint64(-i)) + 1
  191. }
  192. return lenUint(uint64(i))
  193. }
  194. func stringFromMarshal(marshalFunc func([]byte) []byte, sizeFunc func() int) string {
  195. return string(marshalFunc(make([]byte, 0, sizeFunc())))
  196. }