| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
- // SPDX-License-Identifier: MIT
- package sdp
- // Marshal takes a SDP struct to text
- // https://tools.ietf.org/html/rfc4566#section-5
- // Session description
- //
- // v= (protocol version)
- // o= (originator and session identifier)
- // s= (session name)
- // i=* (session information)
- // u=* (URI of description)
- // e=* (email address)
- // p=* (phone number)
- // c=* (connection information -- not required if included in
- // all media)
- // b=* (zero or more bandwidth information lines)
- // One or more time descriptions ("t=" and "r=" lines; see below)
- // z=* (time zone adjustments)
- // k=* (encryption key)
- // a=* (zero or more session attribute lines)
- // Zero or more media descriptions
- //
- // Time description
- //
- // t= (time the session is active)
- // r=* (zero or more repeat times)
- //
- // Media description, if present
- //
- // m= (media name and transport address)
- // i=* (media title)
- // c=* (connection information -- optional if included at
- // session level)
- // b=* (zero or more bandwidth information lines)
- // k=* (encryption key)
- // a=* (zero or more media attribute lines)
- func (s *SessionDescription) Marshal() ([]byte, error) {
- m := make(marshaller, 0, s.MarshalSize())
- m.addKeyValue("v=", s.Version.marshalInto)
- m.addKeyValue("o=", s.Origin.marshalInto)
- m.addKeyValue("s=", s.SessionName.marshalInto)
- if s.SessionInformation != nil {
- m.addKeyValue("i=", s.SessionInformation.marshalInto)
- }
- if s.URI != nil {
- m = append(m, "u="...)
- m = append(m, s.URI.String()...)
- m = append(m, "\r\n"...)
- }
- if s.EmailAddress != nil {
- m.addKeyValue("e=", s.EmailAddress.marshalInto)
- }
- if s.PhoneNumber != nil {
- m.addKeyValue("p=", s.PhoneNumber.marshalInto)
- }
- if s.ConnectionInformation != nil {
- m.addKeyValue("c=", s.ConnectionInformation.marshalInto)
- }
- for _, b := range s.Bandwidth {
- m.addKeyValue("b=", b.marshalInto)
- }
- for _, td := range s.TimeDescriptions {
- m.addKeyValue("t=", td.Timing.marshalInto)
- for _, r := range td.RepeatTimes {
- m.addKeyValue("r=", r.marshalInto)
- }
- }
- if len(s.TimeZones) > 0 {
- m = append(m, "z="...)
- for i, z := range s.TimeZones {
- if i > 0 {
- m = append(m, ' ')
- }
- m = z.marshalInto(m)
- }
- m = append(m, "\r\n"...)
- }
- if s.EncryptionKey != nil {
- m.addKeyValue("k=", s.EncryptionKey.marshalInto)
- }
- for _, a := range s.Attributes {
- m.addKeyValue("a=", a.marshalInto)
- }
- for _, md := range s.MediaDescriptions {
- m.addKeyValue("m=", md.MediaName.marshalInto)
- if md.MediaTitle != nil {
- m.addKeyValue("i=", md.MediaTitle.marshalInto)
- }
- if md.ConnectionInformation != nil {
- m.addKeyValue("c=", md.ConnectionInformation.marshalInto)
- }
- for _, b := range md.Bandwidth {
- m.addKeyValue("b=", b.marshalInto)
- }
- if md.EncryptionKey != nil {
- m.addKeyValue("k=", md.EncryptionKey.marshalInto)
- }
- for _, a := range md.Attributes {
- m.addKeyValue("a=", a.marshalInto)
- }
- }
- return m, nil
- }
- // `$type=` and CRLF size
- const lineBaseSize = 4
- // MarshalSize returns the size of the SessionDescription once marshaled.
- func (s *SessionDescription) MarshalSize() (marshalSize int) {
- marshalSize += lineBaseSize + s.Version.marshalSize()
- marshalSize += lineBaseSize + s.Origin.marshalSize()
- marshalSize += lineBaseSize + s.SessionName.marshalSize()
- if s.SessionInformation != nil {
- marshalSize += lineBaseSize + s.SessionInformation.marshalSize()
- }
- if s.URI != nil {
- marshalSize += lineBaseSize + len(s.URI.String())
- }
- if s.EmailAddress != nil {
- marshalSize += lineBaseSize + s.EmailAddress.marshalSize()
- }
- if s.PhoneNumber != nil {
- marshalSize += lineBaseSize + s.PhoneNumber.marshalSize()
- }
- if s.ConnectionInformation != nil {
- marshalSize += lineBaseSize + s.ConnectionInformation.marshalSize()
- }
- for _, b := range s.Bandwidth {
- marshalSize += lineBaseSize + b.marshalSize()
- }
- for _, td := range s.TimeDescriptions {
- marshalSize += lineBaseSize + td.Timing.marshalSize()
- for _, r := range td.RepeatTimes {
- marshalSize += lineBaseSize + r.marshalSize()
- }
- }
- if len(s.TimeZones) > 0 {
- marshalSize += lineBaseSize
- for i, z := range s.TimeZones {
- if i > 0 {
- marshalSize++
- }
- marshalSize += z.marshalSize()
- }
- }
- if s.EncryptionKey != nil {
- marshalSize += lineBaseSize + s.EncryptionKey.marshalSize()
- }
- for _, a := range s.Attributes {
- marshalSize += lineBaseSize + a.marshalSize()
- }
- for _, md := range s.MediaDescriptions {
- marshalSize += lineBaseSize + md.MediaName.marshalSize()
- if md.MediaTitle != nil {
- marshalSize += lineBaseSize + md.MediaTitle.marshalSize()
- }
- if md.ConnectionInformation != nil {
- marshalSize += lineBaseSize + md.ConnectionInformation.marshalSize()
- }
- for _, b := range md.Bandwidth {
- marshalSize += lineBaseSize + b.marshalSize()
- }
- if md.EncryptionKey != nil {
- marshalSize += lineBaseSize + md.EncryptionKey.marshalSize()
- }
- for _, a := range md.Attributes {
- marshalSize += lineBaseSize + a.marshalSize()
- }
- }
- return marshalSize
- }
- // marshaller contains state during marshaling.
- type marshaller []byte
- func (m *marshaller) addKeyValue(key string, value func([]byte) []byte) {
- *m = append(*m, key...)
- *m = value(*m)
- *m = append(*m, "\r\n"...)
- }
- func lenUint(i uint64) (count int) {
- if i == 0 {
- return 1
- }
- for i != 0 {
- i /= 10
- count++
- }
- return
- }
- func lenInt(i int64) (count int) {
- if i < 0 {
- return lenUint(uint64(-i)) + 1
- }
- return lenUint(uint64(i))
- }
- func stringFromMarshal(marshalFunc func([]byte) []byte, sizeFunc func() int) string {
- return string(marshalFunc(make([]byte, 0, sizeFunc())))
- }
|