// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>// SPDX-License-Identifier: MITpackage rtcpimport ()// SDESType is the item type used in the RTCP SDES control packet.typeSDESTypeuint8// RTP SDES item types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-5const (SDESEndSDESType = iota// end of SDES list RFC 3550, 6.5SDESCNAME// canonical name RFC 3550, 6.5.1SDESName// user name RFC 3550, 6.5.2SDESEmail// user's electronic mail address RFC 3550, 6.5.3SDESPhone// user's phone number RFC 3550, 6.5.4SDESLocation// geographic user location RFC 3550, 6.5.5SDESTool// name of application or tool RFC 3550, 6.5.6SDESNote// notice about the source RFC 3550, 6.5.7SDESPrivate// private extensions RFC 3550, 6.5.8 (not implemented))func ( SDESType) () string {switch {caseSDESEnd:return"END"caseSDESCNAME:return"CNAME"caseSDESName:return"NAME"caseSDESEmail:return"EMAIL"caseSDESPhone:return"PHONE"caseSDESLocation:return"LOC"caseSDESTool:return"TOOL"caseSDESNote:return"NOTE"caseSDESPrivate:return"PRIV"default:returnstring() }}const ( sdesSourceLen = 4 sdesTypeLen = 1 sdesTypeOffset = 0 sdesOctetCountLen = 1 sdesOctetCountOffset = 1 sdesMaxOctetCount = (1 << 8) - 1 sdesTextOffset = 2)// A SourceDescription (SDES) packet describes the sources in an RTP stream.typeSourceDescriptionstruct { Chunks []SourceDescriptionChunk}// NewCNAMESourceDescription creates a new SourceDescription with a single CNAME item.func ( uint32, string) *SourceDescription {return &SourceDescription{Chunks: []SourceDescriptionChunk{{Source: ,Items: []SourceDescriptionItem{{Type: SDESCNAME,Text: , }}, }}, }}// Marshal encodes the SourceDescription in binaryfunc ( SourceDescription) () ([]byte, error) {/* * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| SC | PT=SDES=202 | length | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * chunk | SSRC/CSRC_1 | * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * chunk | SSRC/CSRC_2 | * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */ := make([]byte, .MarshalSize()) := [headerLength:] := 0for , := range .Chunks { , := .Marshal()if != nil {returnnil, }copy([:], ) += len() }iflen(.Chunks) > countMax {returnnil, errTooManyChunks } , := .Header().Marshal()if != nil {returnnil, }copy(, )return , nil}// Unmarshal decodes the SourceDescription from binaryfunc ( *SourceDescription) ( []byte) error {/* * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| SC | PT=SDES=202 | length | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * chunk | SSRC/CSRC_1 | * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * chunk | SSRC/CSRC_2 | * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */varHeaderif := .Unmarshal(); != nil {return }if .Type != TypeSourceDescription {returnerrWrongType }for := headerLength; < len(); {varSourceDescriptionChunkif := .Unmarshal([:]); != nil {return } .Chunks = append(.Chunks, ) += .len() }iflen(.Chunks) != int(.Count) {returnerrInvalidHeader }returnnil}// MarshalSize returns the size of the packet once marshaledfunc ( *SourceDescription) () int { := 0for , := range .Chunks { += .len() }returnheaderLength + }// Header returns the Header associated with this packet.func ( *SourceDescription) () Header {returnHeader{Count: uint8(len(.Chunks)),Type: TypeSourceDescription,Length: uint16((.MarshalSize() / 4) - 1), }}// A SourceDescriptionChunk contains items describing a single RTP sourcetypeSourceDescriptionChunkstruct {// The source (ssrc) or contributing source (csrc) identifier this packet describes Source uint32 Items []SourceDescriptionItem}// Marshal encodes the SourceDescriptionChunk in binaryfunc ( SourceDescriptionChunk) () ([]byte, error) {/* * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * | SSRC/CSRC_1 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */ := make([]byte, sdesSourceLen)binary.BigEndian.PutUint32(, .Source)for , := range .Items { , := .Marshal()if != nil {returnnil, } = append(, ...) }// The list of items in each chunk MUST be terminated by one or more null octets = append(, uint8(SDESEnd))// additional null octets MUST be included if needed to pad until the next 32-bit boundary = append(, make([]byte, getPadding(len()))...)return , nil}// Unmarshal decodes the SourceDescriptionChunk from binaryfunc ( *SourceDescriptionChunk) ( []byte) error {/* * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * | SSRC/CSRC_1 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SDES items | * | ... | * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ */iflen() < (sdesSourceLen + sdesTypeLen) {returnerrPacketTooShort } .Source = binary.BigEndian.Uint32()for := 4; < len(); {if := SDESType([]); == SDESEnd {returnnil }varSourceDescriptionItemif := .Unmarshal([:]); != nil {return } .Items = append(.Items, ) += .Len() }returnerrPacketTooShort}func ( SourceDescriptionChunk) () int { := sdesSourceLenfor , := range .Items { += .Len() } += sdesTypeLen// for terminating null octet// align to 32-bit boundary += getPadding()return}// A SourceDescriptionItem is a part of a SourceDescription that describes a stream.typeSourceDescriptionItemstruct {// The type identifier for this item. eg, SDESCNAME for canonical name description. // // Type zero or SDESEnd is interpreted as the end of an item list and cannot be used. Type SDESType// Text is a unicode text blob associated with the item. Its meaning varies based on the item's Type. Text string}// Len returns the length of the SourceDescriptionItem when encoded as binary.func ( SourceDescriptionItem) () int {/* * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | CNAME=1 | length | user and domain name ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */returnsdesTypeLen + sdesOctetCountLen + len([]byte(.Text))}// Marshal encodes the SourceDescriptionItem in binaryfunc ( SourceDescriptionItem) () ([]byte, error) {/* * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | CNAME=1 | length | user and domain name ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */if .Type == SDESEnd {returnnil, errSDESMissingType } := make([]byte, sdesTypeLen+sdesOctetCountLen) [sdesTypeOffset] = uint8(.Type) := []byte(.Text) := len()if > sdesMaxOctetCount {returnnil, errSDESTextTooLong } [sdesOctetCountOffset] = uint8() = append(, ...)return , nil}// Unmarshal decodes the SourceDescriptionItem from binaryfunc ( *SourceDescriptionItem) ( []byte) error {/* * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | CNAME=1 | length | user and domain name ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */iflen() < (sdesTypeLen + sdesOctetCountLen) {returnerrPacketTooShort } .Type = SDESType([sdesTypeOffset]) := int([sdesOctetCountOffset])ifsdesTextOffset+ > len() {returnerrPacketTooShort } := [sdesTextOffset : sdesTextOffset+] .Text = string()returnnil}// DestinationSSRC returns an array of SSRC values that this packet refers to.func ( *SourceDescription) () []uint32 { := make([]uint32, len(.Chunks))for , := range .Chunks { [] = .Source }return}func ( *SourceDescription) () string { := "Source Description:\n"for , := range .Chunks { += fmt.Sprintf("\t%x: %s\n", .Source, .Items) }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.