// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>// SPDX-License-Identifier: MITpackage rtcpimport ()// The ExtendedReport packet is an Implementation of RTCP Extended// Reports defined in RFC 3611. It is used to convey detailed// information about an RTP stream. Each packet contains one or// more report blocks, each of which conveys a different kind of// information.//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// |V=2|P|reserved | PT=XR=207 | length |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | SSRC |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// : report blocks :// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+typeExtendedReportstruct { SenderSSRC uint32`fmt:"0x%X"` Reports []ReportBlock}// ReportBlock represents a single report within an ExtendedReport// packettypeReportBlockinterface {DestinationSSRC() []uint32 setupBlockHeader() unpackBlockHeader()}// TypeSpecificField as described in RFC 3611 section 4.5. In typical// cases, users of ExtendedReports shouldn't need to access this,// and should instead use the corresponding fields in the actual// report blocks themselves.typeTypeSpecificFielduint8// XRHeader defines the common fields that must appear at the start// of each report block. In typical cases, users of ExtendedReports// shouldn't need to access this. For locally-constructed report// blocks, these values will not be accurate until the corresponding// packet is marshaled.typeXRHeaderstruct { BlockType BlockTypeType TypeSpecific TypeSpecificField`fmt:"0x%X"` BlockLength uint16}// BlockTypeType specifies the type of report in a report blocktypeBlockTypeTypeuint8// Extended Report block types from RFC 3611.const (LossRLEReportBlockType = 1// RFC 3611, section 4.1DuplicateRLEReportBlockType = 2// RFC 3611, section 4.2PacketReceiptTimesReportBlockType = 3// RFC 3611, section 4.3ReceiverReferenceTimeReportBlockType = 4// RFC 3611, section 4.4DLRRReportBlockType = 5// RFC 3611, section 4.5StatisticsSummaryReportBlockType = 6// RFC 3611, section 4.6VoIPMetricsReportBlockType = 7// RFC 3611, section 4.7)// String converts the Extended report block types into readable stringsfunc ( BlockTypeType) () string {switch {caseLossRLEReportBlockType:return"LossRLEReportBlockType"caseDuplicateRLEReportBlockType:return"DuplicateRLEReportBlockType"casePacketReceiptTimesReportBlockType:return"PacketReceiptTimesReportBlockType"caseReceiverReferenceTimeReportBlockType:return"ReceiverReferenceTimeReportBlockType"caseDLRRReportBlockType:return"DLRRReportBlockType"caseStatisticsSummaryReportBlockType:return"StatisticsSummaryReportBlockType"caseVoIPMetricsReportBlockType:return"VoIPMetricsReportBlockType" }returnfmt.Sprintf("invalid value %d", )}// rleReportBlock defines the common structure used by both// Loss RLE report blocks (RFC 3611 §4.1) and Duplicate RLE// report blocks (RFC 3611 §4.2).//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | BT = 1 or 2 | rsvd. | T | block length |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | SSRC of source |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | begin_seq | end_seq |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | chunk 1 | chunk 2 |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// : ... :// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | chunk n-1 | chunk n |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+type rleReportBlock struct {XRHeader T uint8`encoding:"omit"` SSRC uint32`fmt:"0x%X"` BeginSeq uint16 EndSeq uint16 Chunks []Chunk}// Chunk as defined in RFC 3611, section 4.1. These represent information// about packet losses and packet duplication. They have three representations://// Run Length Chunk://// 0 1// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// |C|R| run length |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Bit Vector Chunk://// 0 1// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// |C| bit vector |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Terminating Null Chunk://// 0 1// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+typeChunkuint16// LossRLEReportBlock is used to report information about packet// losses, as described in RFC 3611, section 4.1typeLossRLEReportBlockrleReportBlock// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *LossRLEReportBlock) () []uint32 {return []uint32{.SSRC}}func ( *LossRLEReportBlock) () { .XRHeader.BlockType = LossRLEReportBlockType .XRHeader.TypeSpecific = TypeSpecificField(.T & 0x0F) .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *LossRLEReportBlock) () { .T = uint8(.XRHeader.TypeSpecific) & 0x0F}// DuplicateRLEReportBlock is used to report information about packet// duplication, as described in RFC 3611, section 4.1typeDuplicateRLEReportBlockrleReportBlock// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *DuplicateRLEReportBlock) () []uint32 {return []uint32{.SSRC}}func ( *DuplicateRLEReportBlock) () { .XRHeader.BlockType = DuplicateRLEReportBlockType .XRHeader.TypeSpecific = TypeSpecificField(.T & 0x0F) .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *DuplicateRLEReportBlock) () { .T = uint8(.XRHeader.TypeSpecific) & 0x0F}// ChunkType enumerates the three kinds of chunks described in RFC 3611 section 4.1.typeChunkTypeuint8// These are the valid values that ChunkType can assumeconst (RunLengthChunkType = 0BitVectorChunkType = 1TerminatingNullChunkType = 2)func ( Chunk) () string {switch .Type() {caseRunLengthChunkType: , := .RunType()returnfmt.Sprintf("[RunLength type=%d, length=%d]", , .Value())caseBitVectorChunkType:returnfmt.Sprintf("[BitVector 0b%015b]", .Value())caseTerminatingNullChunkType:return"[TerminatingNull]" }returnfmt.Sprintf("[0x%X]", uint16())}// Type returns the ChunkType that this Chunk representsfunc ( Chunk) () ChunkType {if == 0 {returnTerminatingNullChunkType }returnChunkType( >> 15)}// RunType returns the RunType that this Chunk represents. It is// only valid if ChunkType is RunLengthChunkType.func ( Chunk) () (uint, error) {if .Type() != RunLengthChunkType {return0, errWrongChunkType }returnuint(( >> 14) & 0x01), nil}// Value returns the value represented in this Chunkfunc ( Chunk) () uint {switch .Type() {caseRunLengthChunkType:returnuint( & 0x3FFF)caseBitVectorChunkType:returnuint( & 0x7FFF)caseTerminatingNullChunkType:return0 }returnuint()}// PacketReceiptTimesReportBlock represents a Packet Receipt Times// report block, as described in RFC 3611 section 4.3.//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | BT=3 | rsvd. | T | block length |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | SSRC of source |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | begin_seq | end_seq |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | Receipt time of packet begin_seq |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | Receipt time of packet (begin_seq + 1) mod 65536 |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// : ... :// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | Receipt time of packet (end_seq - 1) mod 65536 |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+typePacketReceiptTimesReportBlockstruct {XRHeader T uint8`encoding:"omit"` SSRC uint32`fmt:"0x%X"` BeginSeq uint16 EndSeq uint16 ReceiptTime []uint32}// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *PacketReceiptTimesReportBlock) () []uint32 {return []uint32{.SSRC}}func ( *PacketReceiptTimesReportBlock) () { .XRHeader.BlockType = PacketReceiptTimesReportBlockType .XRHeader.TypeSpecific = TypeSpecificField(.T & 0x0F) .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *PacketReceiptTimesReportBlock) () { .T = uint8(.XRHeader.TypeSpecific) & 0x0F}// ReceiverReferenceTimeReportBlock encodes a Receiver Reference Time// report block as described in RFC 3611 section 4.4.//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | BT=4 | reserved | block length = 2 |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | NTP timestamp, most significant word |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | NTP timestamp, least significant word |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+typeReceiverReferenceTimeReportBlockstruct {XRHeader NTPTimestamp uint64}// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *ReceiverReferenceTimeReportBlock) () []uint32 {return []uint32{}}func ( *ReceiverReferenceTimeReportBlock) () { .XRHeader.BlockType = ReceiverReferenceTimeReportBlockType .XRHeader.TypeSpecific = 0 .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *ReceiverReferenceTimeReportBlock) () {}// DLRRReportBlock encodes a DLRR Report Block as described in// RFC 3611 section 4.5.//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | BT=5 | reserved | block length |// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+// | SSRC_1 (SSRC of first receiver) | sub-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block// | last RR (LRR) | 1// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | delay since last RR (DLRR) |// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+// | SSRC_2 (SSRC of second receiver) | sub-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block// : ... : 2// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+typeDLRRReportBlockstruct {XRHeader Reports []DLRRReport}// DLRRReport encodes a single report inside a DLRRReportBlock.typeDLRRReportstruct { SSRC uint32`fmt:"0x%X"` LastRR uint32 DLRR uint32}// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *DLRRReportBlock) () []uint32 { := make([]uint32, len(.Reports))for , := range .Reports { [] = .SSRC }return}func ( *DLRRReportBlock) () { .XRHeader.BlockType = DLRRReportBlockType .XRHeader.TypeSpecific = 0 .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *DLRRReportBlock) () {}// StatisticsSummaryReportBlock encodes a Statistics Summary Report// Block as described in RFC 3611, section 4.6.//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | BT=6 |L|D|J|ToH|rsvd.| block length = 9 |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | SSRC of source |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | begin_seq | end_seq |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | lost_packets |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | dup_packets |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | min_jitter |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | max_jitter |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | mean_jitter |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | dev_jitter |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | min_ttl_or_hl | max_ttl_or_hl |mean_ttl_or_hl | dev_ttl_or_hl |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+typeStatisticsSummaryReportBlockstruct {XRHeader LossReports bool`encoding:"omit"` DuplicateReports bool`encoding:"omit"` JitterReports bool`encoding:"omit"` TTLorHopLimit TTLorHopLimitType`encoding:"omit"` SSRC uint32`fmt:"0x%X"` BeginSeq uint16 EndSeq uint16 LostPackets uint32 DupPackets uint32 MinJitter uint32 MaxJitter uint32 MeanJitter uint32 DevJitter uint32 MinTTLOrHL uint8 MaxTTLOrHL uint8 MeanTTLOrHL uint8 DevTTLOrHL uint8}// TTLorHopLimitType encodes values for the ToH field in// a StatisticsSummaryReportBlocktypeTTLorHopLimitTypeuint8// Values for TTLorHopLimitTypeconst (ToHMissing = 0ToHIPv4 = 1ToHIPv6 = 2)func ( TTLorHopLimitType) () string {switch {caseToHMissing:return"[ToH Missing]"caseToHIPv4:return"[ToH = IPv4]"caseToHIPv6:return"[ToH = IPv6]" }return"[ToH Flag is Invalid]"}// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *StatisticsSummaryReportBlock) () []uint32 {return []uint32{.SSRC}}func ( *StatisticsSummaryReportBlock) () { .XRHeader.BlockType = StatisticsSummaryReportBlockType .XRHeader.TypeSpecific = 0x00if .LossReports { .XRHeader.TypeSpecific |= 0x80 }if .DuplicateReports { .XRHeader.TypeSpecific |= 0x40 }if .JitterReports { .XRHeader.TypeSpecific |= 0x20 } .XRHeader.TypeSpecific |= TypeSpecificField((.TTLorHopLimit & 0x03) << 3) .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *StatisticsSummaryReportBlock) () { .LossReports = .XRHeader.TypeSpecific&0x80 != 0 .DuplicateReports = .XRHeader.TypeSpecific&0x40 != 0 .JitterReports = .XRHeader.TypeSpecific&0x20 != 0 .TTLorHopLimit = TTLorHopLimitType((.XRHeader.TypeSpecific & 0x18) >> 3)}// VoIPMetricsReportBlock encodes a VoIP Metrics Report Block as described// in RFC 3611, section 4.7.//// 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//// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | BT=7 | reserved | block length = 8 |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | SSRC of source |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | loss rate | discard rate | burst density | gap density |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | burst duration | gap duration |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | round trip delay | end system delay |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | signal level | noise level | RERL | Gmin |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | R factor | ext. R factor | MOS-LQ | MOS-CQ |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | RX config | reserved | JB nominal |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// | JB maximum | JB abs max |// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+typeVoIPMetricsReportBlockstruct {XRHeader SSRC uint32`fmt:"0x%X"` LossRate uint8 DiscardRate uint8 BurstDensity uint8 GapDensity uint8 BurstDuration uint16 GapDuration uint16 RoundTripDelay uint16 EndSystemDelay uint16 SignalLevel uint8 NoiseLevel uint8 RERL uint8 Gmin uint8 RFactor uint8 ExtRFactor uint8 MOSLQ uint8 MOSCQ uint8 RXConfig uint8 _ uint8 JBNominal uint16 JBMaximum uint16 JBAbsMax uint16}// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *VoIPMetricsReportBlock) () []uint32 {return []uint32{.SSRC}}func ( *VoIPMetricsReportBlock) () { .XRHeader.BlockType = VoIPMetricsReportBlockType .XRHeader.TypeSpecific = 0 .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *VoIPMetricsReportBlock) () {}// UnknownReportBlock is used to store bytes for any report block// that has an unknown Report Block Type.typeUnknownReportBlockstruct {XRHeader Bytes []byte}// DestinationSSRC returns an array of SSRC values that this report block refers to.func ( *UnknownReportBlock) () []uint32 {return []uint32{}}func ( *UnknownReportBlock) () { .XRHeader.BlockLength = uint16(wireSize()/4 - 1)}func ( *UnknownReportBlock) () {}// MarshalSize returns the size of the packet once marshaledfunc ( ExtendedReport) () int {returnwireSize()}// Marshal encodes the ExtendedReport in binaryfunc ( ExtendedReport) () ([]byte, error) {for , := range .Reports { .setupBlockHeader() } := wireSize()// RTCP Header := Header{Type: TypeExtendedReport,Length: uint16( / 4), } , := .Marshal()if != nil {return []byte{}, } += len() := make([]byte, ) := packetBuffer{bytes: } = .write()if != nil {return []byte{}, } = .write()if != nil {return []byte{}, }return , nil}// Unmarshal decodes the ExtendedReport from binaryfunc ( *ExtendedReport) ( []byte) error {varHeaderif := .Unmarshal(); != nil {return }if .Type != TypeExtendedReport {returnerrWrongType } := packetBuffer{bytes: [headerLength:]} := .read(&.SenderSSRC)if != nil {return }forlen(.bytes) > 0 {varReportBlock := := XRHeader{} = .read(&)if != nil {return }switch .BlockType {caseLossRLEReportBlockType: = new(LossRLEReportBlock)caseDuplicateRLEReportBlockType: = new(DuplicateRLEReportBlock)casePacketReceiptTimesReportBlockType: = new(PacketReceiptTimesReportBlock)caseReceiverReferenceTimeReportBlockType: = new(ReceiverReferenceTimeReportBlock)caseDLRRReportBlockType: = new(DLRRReportBlock)caseStatisticsSummaryReportBlockType: = new(StatisticsSummaryReportBlock)caseVoIPMetricsReportBlockType: = new(VoIPMetricsReportBlock)default: = new(UnknownReportBlock) }// We need to limit the amount of data available to // this block to the actual length of the block := (int(.BlockLength) + 1) * 4 := .split() = .read()if != nil {return } .unpackBlockHeader() .Reports = append(.Reports, ) }returnnil}// DestinationSSRC returns an array of SSRC values that this packet refers to.func ( *ExtendedReport) () []uint32 { := make([]uint32, 0, len(.Reports)+1) = append(, .SenderSSRC)for , := range .Reports { = append(, .DestinationSSRC()...) }return}func ( *ExtendedReport) () string {returnstringify()}
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.