直播:后台 JWT 推流、前台画中画;WebRTC 服务与 Nginx WebSocket 代理
Made-with: Cursor
This commit is contained in:
659
server/vendor/github.com/pion/rtcp/extended_report.go
generated
vendored
Normal file
659
server/vendor/github.com/pion/rtcp/extended_report.go
generated
vendored
Normal file
@@ -0,0 +1,659 @@
|
||||
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package rtcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 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 :
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
type ExtendedReport struct {
|
||||
SenderSSRC uint32 `fmt:"0x%X"`
|
||||
Reports []ReportBlock
|
||||
}
|
||||
|
||||
// ReportBlock represents a single report within an ExtendedReport
|
||||
// packet
|
||||
type ReportBlock interface {
|
||||
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.
|
||||
type TypeSpecificField uint8
|
||||
|
||||
// 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.
|
||||
type XRHeader struct {
|
||||
BlockType BlockTypeType
|
||||
TypeSpecific TypeSpecificField `fmt:"0x%X"`
|
||||
BlockLength uint16
|
||||
}
|
||||
|
||||
// BlockTypeType specifies the type of report in a report block
|
||||
type BlockTypeType uint8
|
||||
|
||||
// Extended Report block types from RFC 3611.
|
||||
const (
|
||||
LossRLEReportBlockType = 1 // RFC 3611, section 4.1
|
||||
DuplicateRLEReportBlockType = 2 // RFC 3611, section 4.2
|
||||
PacketReceiptTimesReportBlockType = 3 // RFC 3611, section 4.3
|
||||
ReceiverReferenceTimeReportBlockType = 4 // RFC 3611, section 4.4
|
||||
DLRRReportBlockType = 5 // RFC 3611, section 4.5
|
||||
StatisticsSummaryReportBlockType = 6 // RFC 3611, section 4.6
|
||||
VoIPMetricsReportBlockType = 7 // RFC 3611, section 4.7
|
||||
)
|
||||
|
||||
// String converts the Extended report block types into readable strings
|
||||
func (t BlockTypeType) String() string {
|
||||
switch t {
|
||||
case LossRLEReportBlockType:
|
||||
return "LossRLEReportBlockType"
|
||||
case DuplicateRLEReportBlockType:
|
||||
return "DuplicateRLEReportBlockType"
|
||||
case PacketReceiptTimesReportBlockType:
|
||||
return "PacketReceiptTimesReportBlockType"
|
||||
case ReceiverReferenceTimeReportBlockType:
|
||||
return "ReceiverReferenceTimeReportBlockType"
|
||||
case DLRRReportBlockType:
|
||||
return "DLRRReportBlockType"
|
||||
case StatisticsSummaryReportBlockType:
|
||||
return "StatisticsSummaryReportBlockType"
|
||||
case VoIPMetricsReportBlockType:
|
||||
return "VoIPMetricsReportBlockType"
|
||||
}
|
||||
return fmt.Sprintf("invalid value %d", t)
|
||||
}
|
||||
|
||||
// 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|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
type Chunk uint16
|
||||
|
||||
// LossRLEReportBlock is used to report information about packet
|
||||
// losses, as described in RFC 3611, section 4.1
|
||||
type LossRLEReportBlock rleReportBlock
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this report block refers to.
|
||||
func (b *LossRLEReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{b.SSRC}
|
||||
}
|
||||
|
||||
func (b *LossRLEReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = LossRLEReportBlockType
|
||||
b.XRHeader.TypeSpecific = TypeSpecificField(b.T & 0x0F)
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *LossRLEReportBlock) unpackBlockHeader() {
|
||||
b.T = uint8(b.XRHeader.TypeSpecific) & 0x0F
|
||||
}
|
||||
|
||||
// DuplicateRLEReportBlock is used to report information about packet
|
||||
// duplication, as described in RFC 3611, section 4.1
|
||||
type DuplicateRLEReportBlock rleReportBlock
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this report block refers to.
|
||||
func (b *DuplicateRLEReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{b.SSRC}
|
||||
}
|
||||
|
||||
func (b *DuplicateRLEReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = DuplicateRLEReportBlockType
|
||||
b.XRHeader.TypeSpecific = TypeSpecificField(b.T & 0x0F)
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *DuplicateRLEReportBlock) unpackBlockHeader() {
|
||||
b.T = uint8(b.XRHeader.TypeSpecific) & 0x0F
|
||||
}
|
||||
|
||||
// ChunkType enumerates the three kinds of chunks described in RFC 3611 section 4.1.
|
||||
type ChunkType uint8
|
||||
|
||||
// These are the valid values that ChunkType can assume
|
||||
const (
|
||||
RunLengthChunkType = 0
|
||||
BitVectorChunkType = 1
|
||||
TerminatingNullChunkType = 2
|
||||
)
|
||||
|
||||
func (c Chunk) String() string {
|
||||
switch c.Type() {
|
||||
case RunLengthChunkType:
|
||||
runType, _ := c.RunType()
|
||||
return fmt.Sprintf("[RunLength type=%d, length=%d]", runType, c.Value())
|
||||
case BitVectorChunkType:
|
||||
return fmt.Sprintf("[BitVector 0b%015b]", c.Value())
|
||||
case TerminatingNullChunkType:
|
||||
return "[TerminatingNull]"
|
||||
}
|
||||
return fmt.Sprintf("[0x%X]", uint16(c))
|
||||
}
|
||||
|
||||
// Type returns the ChunkType that this Chunk represents
|
||||
func (c Chunk) Type() ChunkType {
|
||||
if c == 0 {
|
||||
return TerminatingNullChunkType
|
||||
}
|
||||
return ChunkType(c >> 15)
|
||||
}
|
||||
|
||||
// RunType returns the RunType that this Chunk represents. It is
|
||||
// only valid if ChunkType is RunLengthChunkType.
|
||||
func (c Chunk) RunType() (uint, error) {
|
||||
if c.Type() != RunLengthChunkType {
|
||||
return 0, errWrongChunkType
|
||||
}
|
||||
return uint((c >> 14) & 0x01), nil
|
||||
}
|
||||
|
||||
// Value returns the value represented in this Chunk
|
||||
func (c Chunk) Value() uint {
|
||||
switch c.Type() {
|
||||
case RunLengthChunkType:
|
||||
return uint(c & 0x3FFF)
|
||||
case BitVectorChunkType:
|
||||
return uint(c & 0x7FFF)
|
||||
case TerminatingNullChunkType:
|
||||
return 0
|
||||
}
|
||||
return uint(c)
|
||||
}
|
||||
|
||||
// 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 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
type PacketReceiptTimesReportBlock struct {
|
||||
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 (b *PacketReceiptTimesReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{b.SSRC}
|
||||
}
|
||||
|
||||
func (b *PacketReceiptTimesReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = PacketReceiptTimesReportBlockType
|
||||
b.XRHeader.TypeSpecific = TypeSpecificField(b.T & 0x0F)
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *PacketReceiptTimesReportBlock) unpackBlockHeader() {
|
||||
b.T = uint8(b.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 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
type ReceiverReferenceTimeReportBlock struct {
|
||||
XRHeader
|
||||
NTPTimestamp uint64
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this report block refers to.
|
||||
func (b *ReceiverReferenceTimeReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{}
|
||||
}
|
||||
|
||||
func (b *ReceiverReferenceTimeReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = ReceiverReferenceTimeReportBlockType
|
||||
b.XRHeader.TypeSpecific = 0
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *ReceiverReferenceTimeReportBlock) unpackBlockHeader() {
|
||||
}
|
||||
|
||||
// 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
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
type DLRRReportBlock struct {
|
||||
XRHeader
|
||||
Reports []DLRRReport
|
||||
}
|
||||
|
||||
// DLRRReport encodes a single report inside a DLRRReportBlock.
|
||||
type DLRRReport struct {
|
||||
SSRC uint32 `fmt:"0x%X"`
|
||||
LastRR uint32
|
||||
DLRR uint32
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this report block refers to.
|
||||
func (b *DLRRReportBlock) DestinationSSRC() []uint32 {
|
||||
ssrc := make([]uint32, len(b.Reports))
|
||||
for i, r := range b.Reports {
|
||||
ssrc[i] = r.SSRC
|
||||
}
|
||||
return ssrc
|
||||
}
|
||||
|
||||
func (b *DLRRReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = DLRRReportBlockType
|
||||
b.XRHeader.TypeSpecific = 0
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *DLRRReportBlock) unpackBlockHeader() {
|
||||
}
|
||||
|
||||
// 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 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
type StatisticsSummaryReportBlock struct {
|
||||
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 StatisticsSummaryReportBlock
|
||||
type TTLorHopLimitType uint8
|
||||
|
||||
// Values for TTLorHopLimitType
|
||||
const (
|
||||
ToHMissing = 0
|
||||
ToHIPv4 = 1
|
||||
ToHIPv6 = 2
|
||||
)
|
||||
|
||||
func (t TTLorHopLimitType) String() string {
|
||||
switch t {
|
||||
case ToHMissing:
|
||||
return "[ToH Missing]"
|
||||
case ToHIPv4:
|
||||
return "[ToH = IPv4]"
|
||||
case ToHIPv6:
|
||||
return "[ToH = IPv6]"
|
||||
}
|
||||
return "[ToH Flag is Invalid]"
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this report block refers to.
|
||||
func (b *StatisticsSummaryReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{b.SSRC}
|
||||
}
|
||||
|
||||
func (b *StatisticsSummaryReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = StatisticsSummaryReportBlockType
|
||||
b.XRHeader.TypeSpecific = 0x00
|
||||
if b.LossReports {
|
||||
b.XRHeader.TypeSpecific |= 0x80
|
||||
}
|
||||
if b.DuplicateReports {
|
||||
b.XRHeader.TypeSpecific |= 0x40
|
||||
}
|
||||
if b.JitterReports {
|
||||
b.XRHeader.TypeSpecific |= 0x20
|
||||
}
|
||||
b.XRHeader.TypeSpecific |= TypeSpecificField((b.TTLorHopLimit & 0x03) << 3)
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *StatisticsSummaryReportBlock) unpackBlockHeader() {
|
||||
b.LossReports = b.XRHeader.TypeSpecific&0x80 != 0
|
||||
b.DuplicateReports = b.XRHeader.TypeSpecific&0x40 != 0
|
||||
b.JitterReports = b.XRHeader.TypeSpecific&0x20 != 0
|
||||
b.TTLorHopLimit = TTLorHopLimitType((b.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 |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
type VoIPMetricsReportBlock struct {
|
||||
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 (b *VoIPMetricsReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{b.SSRC}
|
||||
}
|
||||
|
||||
func (b *VoIPMetricsReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockType = VoIPMetricsReportBlockType
|
||||
b.XRHeader.TypeSpecific = 0
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *VoIPMetricsReportBlock) unpackBlockHeader() {
|
||||
}
|
||||
|
||||
// UnknownReportBlock is used to store bytes for any report block
|
||||
// that has an unknown Report Block Type.
|
||||
type UnknownReportBlock struct {
|
||||
XRHeader
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this report block refers to.
|
||||
func (b *UnknownReportBlock) DestinationSSRC() []uint32 {
|
||||
return []uint32{}
|
||||
}
|
||||
|
||||
func (b *UnknownReportBlock) setupBlockHeader() {
|
||||
b.XRHeader.BlockLength = uint16(wireSize(b)/4 - 1)
|
||||
}
|
||||
|
||||
func (b *UnknownReportBlock) unpackBlockHeader() {
|
||||
}
|
||||
|
||||
// MarshalSize returns the size of the packet once marshaled
|
||||
func (x ExtendedReport) MarshalSize() int {
|
||||
return wireSize(x)
|
||||
}
|
||||
|
||||
// Marshal encodes the ExtendedReport in binary
|
||||
func (x ExtendedReport) Marshal() ([]byte, error) {
|
||||
for _, p := range x.Reports {
|
||||
p.setupBlockHeader()
|
||||
}
|
||||
|
||||
length := wireSize(x)
|
||||
|
||||
// RTCP Header
|
||||
header := Header{
|
||||
Type: TypeExtendedReport,
|
||||
Length: uint16(length / 4),
|
||||
}
|
||||
headerBuffer, err := header.Marshal()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
length += len(headerBuffer)
|
||||
|
||||
rawPacket := make([]byte, length)
|
||||
buffer := packetBuffer{bytes: rawPacket}
|
||||
|
||||
err = buffer.write(headerBuffer)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
err = buffer.write(x)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return rawPacket, nil
|
||||
}
|
||||
|
||||
// Unmarshal decodes the ExtendedReport from binary
|
||||
func (x *ExtendedReport) Unmarshal(b []byte) error {
|
||||
var header Header
|
||||
if err := header.Unmarshal(b); err != nil {
|
||||
return err
|
||||
}
|
||||
if header.Type != TypeExtendedReport {
|
||||
return errWrongType
|
||||
}
|
||||
|
||||
buffer := packetBuffer{bytes: b[headerLength:]}
|
||||
err := buffer.read(&x.SenderSSRC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for len(buffer.bytes) > 0 {
|
||||
var block ReportBlock
|
||||
|
||||
headerBuffer := buffer
|
||||
xrHeader := XRHeader{}
|
||||
err = headerBuffer.read(&xrHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch xrHeader.BlockType {
|
||||
case LossRLEReportBlockType:
|
||||
block = new(LossRLEReportBlock)
|
||||
case DuplicateRLEReportBlockType:
|
||||
block = new(DuplicateRLEReportBlock)
|
||||
case PacketReceiptTimesReportBlockType:
|
||||
block = new(PacketReceiptTimesReportBlock)
|
||||
case ReceiverReferenceTimeReportBlockType:
|
||||
block = new(ReceiverReferenceTimeReportBlock)
|
||||
case DLRRReportBlockType:
|
||||
block = new(DLRRReportBlock)
|
||||
case StatisticsSummaryReportBlockType:
|
||||
block = new(StatisticsSummaryReportBlock)
|
||||
case VoIPMetricsReportBlockType:
|
||||
block = new(VoIPMetricsReportBlock)
|
||||
default:
|
||||
block = new(UnknownReportBlock)
|
||||
}
|
||||
|
||||
// We need to limit the amount of data available to
|
||||
// this block to the actual length of the block
|
||||
blockLength := (int(xrHeader.BlockLength) + 1) * 4
|
||||
blockBuffer := buffer.split(blockLength)
|
||||
err = blockBuffer.read(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
block.unpackBlockHeader()
|
||||
x.Reports = append(x.Reports, block)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DestinationSSRC returns an array of SSRC values that this packet refers to.
|
||||
func (x *ExtendedReport) DestinationSSRC() []uint32 {
|
||||
ssrc := make([]uint32, 0, len(x.Reports)+1)
|
||||
ssrc = append(ssrc, x.SenderSSRC)
|
||||
for _, p := range x.Reports {
|
||||
ssrc = append(ssrc, p.DestinationSSRC()...)
|
||||
}
|
||||
return ssrc
|
||||
}
|
||||
|
||||
func (x *ExtendedReport) String() string {
|
||||
return stringify(x)
|
||||
}
|
||||
Reference in New Issue
Block a user