Documentation
¶
Overview ¶
Example (Audio2RTPGenerator) ¶
Example on how to generate RTP packets from audio bytes
package main
import (
"bytes"
"fmt"
"os"
"github.com/pion/rtp"
)
type rtpBuffer struct {
buf []rtp.Packet
}
func (b *rtpBuffer) WriteRTP(p *rtp.Packet) error {
b.buf = append(b.buf, *p)
return nil
}
// Example on how to generate RTP packets from audio bytes
func main() {
// Create some audio
audioAlawBuf := make([]byte, 4*160)
copy(audioAlawBuf, bytes.Repeat([]byte("0123456789"), CodecAudioAlaw.Samples16()*2/10))
// Create Packet writer and pass RTP buff
rtpBuf := &rtpBuffer{}
rtpGenerator := NewRTPPacketWriter(rtpBuf, CodecAudioAlaw)
WriteAll(rtpGenerator, audioAlawBuf, 160)
// Now we have RTP packets ready to use from audio
for _, p := range rtpBuf.buf {
fmt.Fprint(os.Stderr, p.String())
}
fmt.Println(len(rtpBuf.buf))
}
Output: 4
Index ¶
- Constants
- Variables
- func CodecsFromSDPRead(formats []string, attrs []string, codecsAudio []Codec) (int, error)
- func CombineSDP(sessions []*MediaSession) []byte
- func Copy(reader io.Reader, writer io.Writer) (int64, error)
- func CopyWithBuf(reader io.Reader, writer io.Writer, payloadBuf []byte) (int64, error)
- func DTMFDecode(payload []byte, d *DTMFEvent) error
- func DTMFEncode(d DTMFEvent) []byte
- func DTMFToRune(dtmf uint8) rune
- func DefaultLogger() *slog.Logger
- func ErrorIsTimeout(err error) bool
- func FractionLostFloat(f uint8) float64
- func GetCurrentNTPTimestamp() uint64
- func NTPTimestamp(t time.Time) uint64
- func NTPToTime(ntpTimestamp uint64) time.Time
- func RTCPUnmarshal(data []byte, packets []rtcp.Packet) (n int, err error)
- func RTPUnmarshal(buf []byte, p *rtp.Packet) error
- func ReadAll(reader io.Reader, sampleSize int) ([]byte, error)
- func SetDefaultLogger(l *slog.Logger)
- func StringRTCP(p rtcp.Packet) string
- func WriteAll(w io.Writer, data []byte, sampleSize int) (int64, error)
- type Codec
- type DTMFEvent
- type MediaSession
- func (s *MediaSession) Close() error
- func (s *MediaSession) CommonCodecs() []Codec
- func (s *MediaSession) Fork() *MediaSession
- func (s *MediaSession) Init() error
- func (s *MediaSession) InitWithListeners(lRTP net.PacketConn, lRTCP net.PacketConn, raddr *net.UDPAddr)
- func (s *MediaSession) InitWithSDP(localSDP []byte) error
- func (s *MediaSession) LocalSDP() []byte
- func (m *MediaSession) ReadRTCP(buf []byte, pkts []rtcp.Packet) (n int, err error)
- func (m *MediaSession) ReadRTCPRaw(buf []byte) (int, error)
- func (m *MediaSession) ReadRTCPRawDeadline(buf []byte, t time.Time) (int, error)
- func (m *MediaSession) ReadRTP(buf []byte, pkt *rtp.Packet) (int, error)
- func (m *MediaSession) ReadRTPRaw(buf []byte) (int, error)
- func (m *MediaSession) ReadRTPRawDeadline(buf []byte, t time.Time) (int, error)
- func (s *MediaSession) RemoteSDP(sdpReceived []byte) error
- func (s *MediaSession) SetRemoteAddr(raddr *net.UDPAddr)
- func (s *MediaSession) StartRTP(rw int8) error
- func (s *MediaSession) StopRTP(rw int8, dur time.Duration) error
- func (m *MediaSession) WriteRTCP(p rtcp.Packet) error
- func (m *MediaSession) WriteRTCPDeadline(p rtcp.Packet, deadline time.Time) error
- func (m *MediaSession) WriteRTCPRaw(data []byte) (int, error)
- func (m *MediaSession) WriteRTCPs(pkts []rtcp.Packet) error
- func (m *MediaSession) WriteRTP(p *rtp.Packet) error
- func (m *MediaSession) WriteRTPRaw(data []byte) (n int, err error)
- type MediaStreamer
- type OnRTPReadStats
- type OnRTPWriteStats
- type RTCPReader
- type RTCPWriter
- type RTCPWriterRaw
- type RTPCReaderRaw
- type RTPDtmfReader
- type RTPDtmfWriter
- type RTPExtendedSequenceNumber
- type RTPPacketReader
- type RTPPacketWriter
- func (p *RTPPacketWriter) DelayTimestamp(ofsset uint32)
- func (p *RTPPacketWriter) InitTimestamp() uint32
- func (p *RTPPacketWriter) ResetTimestamp()
- func (w *RTPPacketWriter) UpdateRTPSession(rtpSess *RTPSession)
- func (p *RTPPacketWriter) Write(b []byte) (int, error)
- func (p *RTPPacketWriter) WriteSamples(payload []byte, sampleRateTimestamp uint32, marker bool, payloadType uint8) (int, error)
- func (w *RTPPacketWriter) Writer() RTPWriter
- type RTPReadStats
- type RTPReader
- type RTPReaderRaw
- type RTPSession
- func (s *RTPSession) Close() error
- func (s *RTPSession) Monitor() error
- func (s *RTPSession) MonitorBackground() error
- func (s *RTPSession) OnReadRTCP(f func(pkt rtcp.Packet, rtpStats RTPReadStats))
- func (s *RTPSession) OnWriteRTCP(f func(pkt rtcp.Packet, rtpStats RTPWriteStats))
- func (s *RTPSession) ReadRTP(b []byte, readPkt *rtp.Packet) (n int, err error)
- func (s *RTPSession) ReadRTPRaw(buf []byte) (int, error)
- func (s *RTPSession) ReadStats() RTPReadStats
- func (s *RTPSession) WriteRTP(pkt *rtp.Packet) error
- func (s *RTPSession) WriteRTPRaw(buf []byte) (int, error)
- func (s *RTPSession) WriteStats() RTPWriteStats
- type RTPStatsReader
- type RTPStatsWriter
- type RTPWriteStats
- type RTPWriter
- type RTPWriterRaw
Examples ¶
Constants ¶
const ( SRTPAes128CmHmacSha1_80 uint16 = uint16(srtp.ProtectionProfileAes128CmHmacSha1_80) SRTPAes256CmHmacSha1_80 uint16 = uint16(srtp.ProtectionProfileAes256CmHmacSha1_80) )
Variables ¶
var ( // Here are some codec constants that can be reused CodecAudioUlaw = Codec{PayloadType: 0, SampleRate: 8000, SampleDur: 20 * time.Millisecond, NumChannels: 1, Name: "PCMU"} CodecAudioAlaw = Codec{PayloadType: 8, SampleRate: 8000, SampleDur: 20 * time.Millisecond, NumChannels: 1, Name: "PCMA"} CodecAudioOpus = Codec{PayloadType: 96, SampleRate: 48000, SampleDur: 20 * time.Millisecond, NumChannels: 2, Name: "opus"} CodecTelephoneEvent8000 = Codec{PayloadType: 101, SampleRate: 8000, SampleDur: 20 * time.Millisecond, NumChannels: 1, Name: "telephone-event"} // Video codecs // H.264 is the most common video codec for SIP CodecVideoH264 = Codec{PayloadType: 99, SampleRate: 90000, SampleDur: 33 * time.Millisecond, NumChannels: 1, Name: "H264"} // VP8 is commonly used in WebRTC CodecVideoVP8 = Codec{PayloadType: 103, SampleRate: 90000, SampleDur: 33 * time.Millisecond, NumChannels: 1, Name: "VP8"} // VP9 is a newer codec CodecVideoVP9 = Codec{PayloadType: 106, SampleRate: 90000, SampleDur: 33 * time.Millisecond, NumChannels: 1, Name: "VP9"} )
var ( // RTPPortStart and RTPPortEnd allows defining rtp port range for media RTPPortStart = 0 RTPPortEnd = 0 // When reading RTP use at least MTU size. Increase this RTPBufSize = 1500 RTPDebug = false RTCPDebug = false // RTPProfileSAVPDisable disables offering RTP/SAVP and keeps standard RTP/AVP for backward compatibilit needs // // Experimental RTPProfileSAVPDisable = false )
var ( ErrRTPSequenceOutOfOrder = errors.New("out of order") ErrRTPSequenceBad = errors.New("bad sequence") ErrRTPSequnceDuplicate = errors.New("sequence duplicate") )
var ( DefaultOnReadRTCP func(pkt rtcp.Packet, rtpStats RTPReadStats) = nil DefaultOnWriteRTCP func(pkt rtcp.Packet, rtpStats RTPWriteStats) = nil )
Functions ¶
func CodecsFromSDPRead ¶
CodecsFromSDP will try to parse as much as possible, but it will return also error in case some properties could not be read You can take what is parsed or return error
func CombineSDP ¶ added in v0.21.3
func CombineSDP(sessions []*MediaSession) []byte
CombineSDP combines SDP from multiple media sessions (e.g., audio and video) into a single SDP with multiple media descriptions
func CopyWithBuf ¶
CopyWithBuf is simple and strict compared to io.CopyBuffer. ReadFrom and WriteTo is not considered and due to RTP buf requirement it can lead to different buffer size passing
func DTMFDecode ¶
DecodeRTPPayload decodes an RTP payload into a DTMF event
func DTMFEncode ¶
func DTMFToRune ¶
func DefaultLogger ¶
func ErrorIsTimeout ¶
func FractionLostFloat ¶
func GetCurrentNTPTimestamp ¶
func GetCurrentNTPTimestamp() uint64
func NTPTimestamp ¶
func RTCPUnmarshal ¶
RTCPUnmarshal is improved version based on pion/rtcp where we allow caller to define and control buffer of rtcp packets. This also reduces one allocation NOTE: data is still referenced in packet buffer
func RTPUnmarshal ¶
Experimental
RTPUnmarshal temporarly solution to provide more optimized unmarshal version based on pion/rtp it does not preserve any buffer reference which allows reusage
TODO build RTP header unmarshaller for VOIP needs
func SetDefaultLogger ¶
SetDefaultLogger sets default logger that will be used withing sip package Must be called before any usage of library
func StringRTCP ¶
Types ¶
type Codec ¶
type Codec struct {
Name string
PayloadType uint8
SampleRate uint32
SampleDur time.Duration
NumChannels int // 1 or 2
}
func CodecAudioFromList ¶
func CodecAudioFromSession ¶
func CodecAudioFromSession(s *MediaSession) Codec
func CodecFromPayloadType
deprecated
func CodecFromSession ¶
func CodecFromSession(s *MediaSession) Codec
CodecFromSession returns the first codec from the session, whether audio or video It prefers filterCodecs (negotiated codecs) over Codecs
func (*Codec) SampleTimestamp ¶
SampleTimestamp returns number of samples as RTP Timestamp measure
type DTMFEvent ¶
DTMFEvent represents a DTMF event
func RTPDTMFEncode8000 ¶
RTPDTMFEncode8000 creates series of DTMF redudant events which should be encoded as payload It is currently only 8000 sample rate considered for telophone event
type MediaSession ¶
type MediaSession struct {
// MediaType is the type of media: "audio" or "video"
MediaType string
// Codecs are initial list of Codecs that would be used in SDP generation
Codecs []Codec
// Mode is sdp mode. Check consts sdp.ModeRecvOnly etc...
Mode string
// Laddr our local address which has full IP and port after media session creation
Laddr net.UDPAddr
// Raddr is our target remote address. Normally it is resolved by SDP parsing.
Raddr net.UDPAddr
// ExternalIP that should be used for building SDP
ExternalIP net.IP
SecureRTP int // 0 none, 1 - SDES
// TODO support multile for offering
SRTPAlg uint16
// contains filtered or unexported fields
}
func NewMediaSession ¶
func NewMediaSession(ip net.IP, port int) (s *MediaSession, e error)
func NewVideoMediaSession ¶ added in v0.21.3
func NewVideoMediaSession(ip net.IP, port int) (s *MediaSession, e error)
NewVideoMediaSession creates a new video media session
func (*MediaSession) Close ¶
func (s *MediaSession) Close() error
func (*MediaSession) CommonCodecs ¶
func (s *MediaSession) CommonCodecs() []Codec
CommonCodecs returns common codecs if negotiation is finished, that is Local and Remote SDP are exchanged NOTE: Not thread safe, should be called after negotiation or session must be Forked
func (*MediaSession) Fork ¶
func (s *MediaSession) Fork() *MediaSession
Fork is special call to be used in case when there is session update It preserves pointer to same conneciton but rest is remobed After this call it still expected that
func (*MediaSession) Init ¶
func (s *MediaSession) Init() error
Init should be called if session is created manually Use NewMediaSession for default building
func (*MediaSession) InitWithListeners ¶
func (s *MediaSession) InitWithListeners(lRTP net.PacketConn, lRTCP net.PacketConn, raddr *net.UDPAddr)
func (*MediaSession) InitWithSDP ¶
func (s *MediaSession) InitWithSDP(localSDP []byte) error
InitWithSDP allows creating media session with own SDP and bypassing other needs
func (*MediaSession) LocalSDP ¶
func (s *MediaSession) LocalSDP() []byte
LocalSDP generates SDP based on local settings and remote SDP It should never be called in parallel to RemoteSDP, as it is expected serial process
func (*MediaSession) ReadRTCP ¶
ReadRTCP is optimized reads and unmarshals RTCP packets. Buffers is only used for unmarshaling. Caller needs to be aware of size this buffer and allign with MTU
func (*MediaSession) ReadRTCPRaw ¶
func (m *MediaSession) ReadRTCPRaw(buf []byte) (int, error)
func (*MediaSession) ReadRTCPRawDeadline ¶
func (*MediaSession) ReadRTP ¶
ReadRTP reads data from network and parses to pkt buffer is passed in order to avoid extra allocs
func (*MediaSession) ReadRTPRaw ¶
func (m *MediaSession) ReadRTPRaw(buf []byte) (int, error)
func (*MediaSession) ReadRTPRawDeadline ¶
func (*MediaSession) RemoteSDP ¶
func (s *MediaSession) RemoteSDP(sdpReceived []byte) error
func (*MediaSession) SetRemoteAddr ¶
func (s *MediaSession) SetRemoteAddr(raddr *net.UDPAddr)
SetRemoteAddr is helper to set Raddr and rtcp address. It is not thread safe
func (*MediaSession) StartRTP ¶
func (s *MediaSession) StartRTP(rw int8) error
func (*MediaSession) WriteRTCPDeadline ¶
func (*MediaSession) WriteRTCPRaw ¶
func (m *MediaSession) WriteRTCPRaw(data []byte) (int, error)
func (*MediaSession) WriteRTCPs ¶
func (m *MediaSession) WriteRTCPs(pkts []rtcp.Packet) error
Use this to write Multi RTCP packets if they can fit in MTU=1500
func (*MediaSession) WriteRTPRaw ¶
func (m *MediaSession) WriteRTPRaw(data []byte) (n int, err error)
type MediaStreamer ¶
type MediaStreamer interface {
MediaStream(s *MediaSession) error
}
type OnRTPReadStats ¶
type OnRTPReadStats func(stats RTPReadStats)
type OnRTPWriteStats ¶
type OnRTPWriteStats func(stats RTPWriteStats)
type RTCPReader ¶
type RTCPWriter ¶
type RTCPWriterRaw ¶
type RTPCReaderRaw ¶
type RTPDtmfReader ¶
type RTPDtmfReader struct {
// contains filtered or unexported fields
}
func NewRTPDTMFReader ¶
func NewRTPDTMFReader(codec Codec, packetReader *RTPPacketReader, reader io.Reader) *RTPDtmfReader
RTP DTMF writer is midleware for reading DTMF events It reads from io Reader and checks packet Reader
func (*RTPDtmfReader) Read ¶
func (w *RTPDtmfReader) Read(b []byte) (int, error)
Write is RTP io.Writer which adds more sync mechanism
func (*RTPDtmfReader) ReadDTMF ¶
func (w *RTPDtmfReader) ReadDTMF() (rune, bool)
type RTPDtmfWriter ¶
type RTPDtmfWriter struct {
// contains filtered or unexported fields
}
func NewRTPDTMFWriter ¶
func NewRTPDTMFWriter(codec Codec, rtpPacketizer *RTPPacketWriter, writer io.Writer) *RTPDtmfWriter
RTP DTMF writer is midleware for passing RTP DTMF event. If it is chained it uses to block writer while writing DTFM events
func (*RTPDtmfWriter) Write ¶
func (w *RTPDtmfWriter) Write(b []byte) (int, error)
Write is RTP io.Writer which adds more sync mechanism
func (*RTPDtmfWriter) WriteDTMF ¶
func (w *RTPDtmfWriter) WriteDTMF(dtmf rune) error
type RTPExtendedSequenceNumber ¶
type RTPExtendedSequenceNumber struct {
// contains filtered or unexported fields
}
RTPExtendedSequenceNumber is embedable/ replacable sequnce number generator For thread safety you should wrap it
func NewRTPSequencer ¶
func NewRTPSequencer() RTPExtendedSequenceNumber
func (*RTPExtendedSequenceNumber) InitSeq ¶
func (sn *RTPExtendedSequenceNumber) InitSeq(seq uint16)
func (*RTPExtendedSequenceNumber) NextSeqNumber ¶
func (s *RTPExtendedSequenceNumber) NextSeqNumber() uint16
func (*RTPExtendedSequenceNumber) ReadExtendedSeq ¶
func (sn *RTPExtendedSequenceNumber) ReadExtendedSeq() uint64
func (*RTPExtendedSequenceNumber) UpdateSeq ¶
func (sn *RTPExtendedSequenceNumber) UpdateSeq(seq uint16) error
Based on https://datatracker.ietf.org/doc/html/rfc1889#appendix-A.2
type RTPPacketReader ¶
type RTPPacketReader struct {
// PacketHeader is stored after calling Read
// Safe to read only in same goroutine as Read
PacketHeader rtp.Header
// contains filtered or unexported fields
}
RTPPacketReader reads RTP packet and extracts payload and header
func NewRTPPacketReader ¶
func NewRTPPacketReader(reader RTPReader, codec Codec) *RTPPacketReader
func NewRTPPacketReaderSession ¶
func NewRTPPacketReaderSession(sess *RTPSession) *RTPPacketReader
NewRTPPacketReaderSession just helper constructor
func (*RTPPacketReader) Read ¶
func (r *RTPPacketReader) Read(b []byte) (int, error)
Read Implements io.Reader and extracts Payload from RTP packet has no input queue or sorting control of packets Buffer is used for reading headers and Headers are stored in PacketHeader
NOTE: Consider that if you are passsing smaller buffer than RTP header+payload, io.ErrShortBuffer is returned
func (*RTPPacketReader) Reader ¶
func (r *RTPPacketReader) Reader() RTPReader
func (*RTPPacketReader) UpdateRTPSession ¶
func (r *RTPPacketReader) UpdateRTPSession(rtpSess *RTPSession)
func (*RTPPacketReader) UpdateReader ¶
func (r *RTPPacketReader) UpdateReader(reader RTPReader)
type RTPPacketWriter ¶
type RTPPacketWriter struct {
// After each write packet header is saved for more reading
PacketHeader rtp.Header
// SSRC is readOnly and it is not changed
SSRC uint32
// contains filtered or unexported fields
}
RTPPacketWriter packetize any payload before pushing to active media session It creates SSRC as identifier and all packets sent will be with this SSRC For multiple streams, multiple RTP Writer needs to be created
func NewRTPPacketWriter ¶
func NewRTPPacketWriter(writer RTPWriter, codec Codec) *RTPPacketWriter
RTPPacketWriter packetize payload in RTP packet before passing on media session Not having: - random Timestamp - allow different clock rate - CSRC contribution source - Silence detection and marker set updateClockRate- Padding and encryyption
func NewRTPPacketWriterSession ¶
func NewRTPPacketWriterSession(sess *RTPSession) *RTPPacketWriter
NewRTPPacketWriterSession creates RTPPacketWriter and attaches RTP Session expected values
func (*RTPPacketWriter) DelayTimestamp ¶
func (p *RTPPacketWriter) DelayTimestamp(ofsset uint32)
func (*RTPPacketWriter) InitTimestamp ¶
func (p *RTPPacketWriter) InitTimestamp() uint32
InitTimestamp returns init RTP timestamp
func (*RTPPacketWriter) ResetTimestamp ¶
func (p *RTPPacketWriter) ResetTimestamp()
ResetTimestamp can mark new stream comming. If stream is continuous it will add timestamp difference MUST Not be called during stream Write
func (*RTPPacketWriter) UpdateRTPSession ¶
func (w *RTPPacketWriter) UpdateRTPSession(rtpSess *RTPSession)
UpdateRTPSession updates rtp writer from current rtp session due to REINVITE It is expected that this is now new RTP Session and it is expected tha: - Statistics will be reset (SSRC=0) -> Fresh Start of Quality monitoring - Should not lead inacurate reporting - In case CODEC change than RTP should reset stats anyway
func (*RTPPacketWriter) Write ¶
func (p *RTPPacketWriter) Write(b []byte) (int, error)
Write implements io.Writer and does payload RTP packetization Media clock rate is determined For more control or dynamic payload WriteSamples can be used It is not thread safe and order of payload frames is required
func (*RTPPacketWriter) WriteSamples ¶
func (p *RTPPacketWriter) WriteSamples(payload []byte, sampleRateTimestamp uint32, marker bool, payloadType uint8) (int, error)
WriteSamples allows to skip default packet rate. This is useful if you need to write different payload but keeping same SSRC
func (*RTPPacketWriter) Writer ¶
func (w *RTPPacketWriter) Writer() RTPWriter
type RTPReadStats ¶
type RTPReadStats struct {
SSRC uint32
FirstPktSequenceNumber uint16
LastSequenceNumber uint16
// tracks first pkt seq in this interval to calculate loss of packets
IntervalFirstPktSeqNum uint16
IntervalPacketsCount uint16
PacketsCount uint64
OctetCount uint64
// RTP reading stats
SampleRate uint32
// Round TRIP Time based on LSR and DLSR
RTT time.Duration
// contains filtered or unexported fields
}
Some of fields here are exported (as readonly) intentionally
type RTPReaderRaw ¶
type RTPSession ¶
type RTPSession struct {
// Keep pointers at top to reduce GC
Sess *MediaSession
// contains filtered or unexported fields
}
func NewRTPSession ¶
func NewRTPSession(sess *MediaSession) *RTPSession
RTP session creates new RTP reader/writer from session
func (*RTPSession) Close ¶
func (s *RTPSession) Close() error
func (*RTPSession) Monitor ¶
func (s *RTPSession) Monitor() error
Monitor starts reading RTCP and monitoring media quality
func (*RTPSession) MonitorBackground ¶
func (s *RTPSession) MonitorBackground() error
MonitorBackground is helper to keep monitoring in background MUST Be called after session REMOTE SDP is parsed
func (*RTPSession) OnReadRTCP ¶
func (s *RTPSession) OnReadRTCP(f func(pkt rtcp.Packet, rtpStats RTPReadStats))
func (*RTPSession) OnWriteRTCP ¶
func (s *RTPSession) OnWriteRTCP(f func(pkt rtcp.Packet, rtpStats RTPWriteStats))
func (*RTPSession) ReadRTP ¶
ReadRTP reads RTP NOTE: For RTCP we may read some properties of media session. Do not run this until full media session is negotiated. For updating media, media session forking must be done!
func (*RTPSession) ReadRTPRaw ¶
func (s *RTPSession) ReadRTPRaw(buf []byte) (int, error)
func (*RTPSession) ReadStats ¶
func (s *RTPSession) ReadStats() RTPReadStats
func (*RTPSession) WriteRTPRaw ¶
func (s *RTPSession) WriteRTPRaw(buf []byte) (int, error)
func (*RTPSession) WriteStats ¶
func (s *RTPSession) WriteStats() RTPWriteStats
type RTPStatsReader ¶
type RTPStatsReader struct {
// Reader should be your AudioReade or any other interceptor RTP reader that is reading audio stream
Reader io.Reader
RTPSession *RTPSession
// OnRTPReadStats is fired each time on Read RTP. Must not block
OnRTPReadStats OnRTPReadStats
}
type RTPStatsWriter ¶
type RTPStatsWriter struct {
// Writer should be your Writer or any other interceptor RTP writer that is reading audio stream
Writer io.Writer
RTPSession *RTPSession
// ONRTPWriteStats is fired each time on Read RTP. Must not block
OnRTPWriteStats OnRTPWriteStats
}
type RTPWriteStats ¶
type RTPWriteStats struct {
SSRC uint32
// RTCP stats
PacketsCount uint64
OctetCount uint64
// contains filtered or unexported fields
}
Some of fields here are exported (as readonly) intentionally