2024-06-05 20:10:03 +00:00
|
|
|
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
|
|
|
// SPDX-License-Identifier: MIT
|
2022-03-10 09:44:48 +00:00
|
|
|
|
2024-06-05 20:10:03 +00:00
|
|
|
package sdp
|
2022-03-10 09:44:48 +00:00
|
|
|
|
|
|
|
// Marshal takes a SDP struct to text
|
|
|
|
// https://tools.ietf.org/html/rfc4566#section-5
|
|
|
|
// Session description
|
2024-06-05 20:10:03 +00:00
|
|
|
//
|
|
|
|
// 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
|
2022-03-10 09:44:48 +00:00
|
|
|
//
|
|
|
|
// Time description
|
2024-06-05 20:10:03 +00:00
|
|
|
//
|
|
|
|
// t= (time the session is active)
|
|
|
|
// r=* (zero or more repeat times)
|
2022-03-10 09:44:48 +00:00
|
|
|
//
|
|
|
|
// Media description, if present
|
2024-06-05 20:10:03 +00:00
|
|
|
//
|
|
|
|
// 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)
|
2022-03-10 09:44:48 +00:00
|
|
|
func (s *SessionDescription) Marshal() ([]byte, error) {
|
2024-06-05 20:10:03 +00:00
|
|
|
m := make(marshaller, 0, s.MarshalSize())
|
2022-03-10 09:44:48 +00:00
|
|
|
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("v=", s.Version.marshalInto)
|
|
|
|
m.addKeyValue("o=", s.Origin.marshalInto)
|
|
|
|
m.addKeyValue("s=", s.SessionName.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
|
|
|
|
if s.SessionInformation != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("i=", s.SessionInformation.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if s.URI != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m = append(m, "u="...)
|
|
|
|
m = append(m, s.URI.String()...)
|
|
|
|
m = append(m, "\r\n"...)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if s.EmailAddress != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("e=", s.EmailAddress.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if s.PhoneNumber != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("p=", s.PhoneNumber.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if s.ConnectionInformation != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("c=", s.ConnectionInformation.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, b := range s.Bandwidth {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("b=", b.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, td := range s.TimeDescriptions {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("t=", td.Timing.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
for _, r := range td.RepeatTimes {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("r=", r.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(s.TimeZones) > 0 {
|
2024-06-05 20:10:03 +00:00
|
|
|
m = append(m, "z="...)
|
2022-03-10 09:44:48 +00:00
|
|
|
for i, z := range s.TimeZones {
|
|
|
|
if i > 0 {
|
2024-06-05 20:10:03 +00:00
|
|
|
m = append(m, ' ')
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
2024-06-05 20:10:03 +00:00
|
|
|
m = z.marshalInto(m)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
2024-06-05 20:10:03 +00:00
|
|
|
m = append(m, "\r\n"...)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if s.EncryptionKey != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("k=", s.EncryptionKey.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, a := range s.Attributes {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("a=", a.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, md := range s.MediaDescriptions {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("m=", md.MediaName.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
|
|
|
|
if md.MediaTitle != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("i=", md.MediaTitle.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if md.ConnectionInformation != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("c=", md.ConnectionInformation.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, b := range md.Bandwidth {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("b=", b.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if md.EncryptionKey != nil {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("k=", md.EncryptionKey.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, a := range md.Attributes {
|
2024-06-05 20:10:03 +00:00
|
|
|
m.addKeyValue("a=", a.marshalInto)
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-05 20:10:03 +00:00
|
|
|
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
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// marshaller contains state during marshaling.
|
|
|
|
type marshaller []byte
|
|
|
|
|
2024-06-05 20:10:03 +00:00
|
|
|
func (m *marshaller) addKeyValue(key string, value func([]byte) []byte) {
|
2022-03-10 09:44:48 +00:00
|
|
|
*m = append(*m, key...)
|
2024-06-05 20:10:03 +00:00
|
|
|
*m = value(*m)
|
2022-03-10 09:44:48 +00:00
|
|
|
*m = append(*m, "\r\n"...)
|
|
|
|
}
|
|
|
|
|
2024-06-05 20:10:03 +00:00
|
|
|
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())))
|
2022-03-10 09:44:48 +00:00
|
|
|
}
|