media

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2024 License: BSD-2-Clause Imports: 16 Imported by: 6

README

media

Go Report Card Coverage License GitHub go.mod Go version

is GO library designed handling real time media for usage with sipgo It has APIs for creating and running protocols like SDP, RTP, RTCP.

Library is currently focused only to provide VOIP needs and removing complexity. As with sipgo focus is to provide minimal GC hits and latency.

Tools using this

Features:

  • Simple SDP build with formats alaw,ulaw,dtmf
  • RTP/RTCP receiving and logging
  • Extendable MediaSession handling for RTP/RTCP handling (ex microphone,speaker)
  • DTMF encoder, decoder via RFC4733
  • Minimal SDP package for audio
  • Media Session, RTP Session handling
  • RTCP monitoring
  • SDP codec fields manipulating
  • ... who knows

IO flow

Reader: AudioDecoder<->RTPPacketReader<->RTPSession<->MediaSession

Writer: AudioEncoder<->RTPPackerWriter<->RTPSession<->MediaSession

more docs...

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	CodecAudioUlaw = Codec{PayloadType: 0, SampleRate: 8000, SampleDur: 20 * time.Millisecond}
	CodecAudioAlaw = Codec{PayloadType: 8, SampleRate: 8000, SampleDur: 20 * time.Millisecond}
)
View Source
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
)
View Source
var (
	ErrRTPSequenceOutOfOrder = errors.New("out of order")
	ErrRTPSequenceBad        = errors.New("bad sequence")
	ErrRTPSequnceDuplicate   = errors.New("sequence duplicate")
)

Functions

func DTMFDecode

func DTMFDecode(payload []byte, d *DTMFEvent) error

DecodeRTPPayload decodes an RTP payload into a DTMF event

func DTMFEncode

func DTMFEncode(d DTMFEvent) []byte

func FractionLostFloat

func FractionLostFloat(f uint8) float64

func GetCurrentNTPTimestamp

func GetCurrentNTPTimestamp() uint64

func NTPTimestamp

func NTPTimestamp(t time.Time) uint64

func NTPToTime

func NTPToTime(ntpTimestamp uint64) time.Time

func RTCPUnmarshal added in v0.2.0

func RTCPUnmarshal(data []byte, packets []rtcp.Packet) (n int, err error)

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 added in v0.2.0

func RTPUnmarshal(buf []byte, p *rtp.Packet) error

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 SendDummyRTP

func SendDummyRTP(rtpConn *net.UDPConn, raddr net.Addr)

Types

type Codec added in v0.2.0

type Codec struct {
	PayloadType uint8
	SampleRate  uint32
	SampleDur   time.Duration
}

func (*Codec) SampleTimestamp added in v0.2.0

func (c *Codec) SampleTimestamp() uint32

type DTMFEvent

type DTMFEvent struct {
	Event      uint8
	EndOfEvent bool
	Volume     uint8
	Duration   uint16
}

DTMFEvent represents a DTMF event

func RTPDTMFEncode

func RTPDTMFEncode(char rune) []DTMFEvent

RTPDTMFEncode creates series of DTMF redudant events which should be encoded as payload It is currently only 8000 sample rate considered for telophone event

func (*DTMFEvent) String

func (ev *DTMFEvent) String() string

type MediaSession

type MediaSession struct {
	// Raddr is our target remote address. Normally it is resolved by SDP parsing.
	// Checkout SetRemoteAddr
	Raddr *net.UDPAddr
	// Laddr our local address which has full IP and port after media session creation
	Laddr *net.UDPAddr

	// SDP stuff
	// Depending of negotiation this can change.
	Formats sdp.Formats
	Mode    sdp.Mode
	// contains filtered or unexported fields
}

MediaSession represents active media session with RTP/RTCP

func NewMediaSession

func NewMediaSession(laddr *net.UDPAddr) (s *MediaSession, e error)

func (*MediaSession) Close

func (s *MediaSession) Close()

func (*MediaSession) Fork added in v0.2.0

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) LocalSDP

func (s *MediaSession) LocalSDP() []byte

func (*MediaSession) ReadRTCP

func (m *MediaSession) ReadRTCP(buf []byte, pkts []rtcp.Packet) (n int, err error)

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 (m *MediaSession) ReadRTCPRawDeadline(buf []byte, t time.Time) (int, error)

func (*MediaSession) ReadRTP

func (m *MediaSession) ReadRTP(buf []byte, pkt *rtp.Packet) error

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 (m *MediaSession) ReadRTPRawDeadline(buf []byte, t time.Time) (int, error)

func (*MediaSession) RemoteSDP

func (s *MediaSession) RemoteSDP(sdpReceived []byte) error

func (*MediaSession) SetLogger

func (s *MediaSession) SetLogger(log zerolog.Logger)

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) WriteRTCP

func (m *MediaSession) WriteRTCP(p rtcp.Packet) error

func (*MediaSession) WriteRTCPDeadline

func (m *MediaSession) WriteRTCPDeadline(p rtcp.Packet, deadline time.Time) error

func (*MediaSession) WriteRTCPRaw added in v0.2.0

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) WriteRTP

func (m *MediaSession) WriteRTP(p *rtp.Packet) error

func (*MediaSession) WriteRTPRaw

func (m *MediaSession) WriteRTPRaw(data []byte) (n int, err error)

type MediaStreamer

type MediaStreamer interface {
	MediaStream(s *MediaSession) error
}

type RTCPReader added in v0.2.0

type RTCPReader interface {
	ReadRTCP(buf []byte, pkts []rtcp.Packet) (n int, err error)
}

type RTCPWriter added in v0.2.0

type RTCPWriter interface {
	WriteRTCP(p rtcp.Packet) error
}

type RTCPWriterRaw added in v0.2.0

type RTCPWriterRaw interface {
	WriteRTCPRaw(buf []byte) (int, error) // -> io.Writer
}

type RTPCReaderRaw added in v0.2.0

type RTPCReaderRaw interface {
	ReadRTCPRaw(buf []byte) (int, 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 added in v0.2.0

type RTPPacketReader struct {
	Sess       *MediaSession
	RTPSession *RTPSession
	Reader     RTPReader

	// Deprecated
	//
	// Should not be used
	OnRTP func(pkt *rtp.Packet)

	// PacketHeader is stored after calling Read this will be stored before returning
	PacketHeader rtp.Header
	PayloadType  uint8
	// contains filtered or unexported fields
}

RTPPacketReader reads RTP packet and extracts payload and header

func NewRTPPacketReader added in v0.2.0

func NewRTPPacketReader(reader RTPReader, codec Codec) *RTPPacketReader

func NewRTPPacketReaderMedia added in v0.2.0

func NewRTPPacketReaderMedia(sess *MediaSession) *RTPPacketReader

NewRTPWriterMedia is left for backward compability. It does not add RTCP reporting It talks directly to network

func NewRTPPacketReaderSession added in v0.2.0

func NewRTPPacketReaderSession(sess *RTPSession) *RTPPacketReader

RTP reader consumes samples of audio from RTP session Use NewRTPSession to construct RTP session

func (*RTPPacketReader) Read added in v0.2.0

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

type RTPPacketReaderConcurent added in v0.2.0

type RTPPacketReaderConcurent struct {
	*RTPPacketReader
	// contains filtered or unexported fields
}

Experimental

RTPPacketReaderConcurent allows updating RTPSession on RTPWriter and more (in case of regonation)

func (*RTPPacketReaderConcurent) Read added in v0.2.0

func (r *RTPPacketReaderConcurent) Read(b []byte) (int, error)

func (*RTPPacketReaderConcurent) SetRTPReader added in v0.2.0

func (r *RTPPacketReaderConcurent) SetRTPReader(rtpReader *RTPPacketReader)

func (*RTPPacketReaderConcurent) SetRTPSession added in v0.2.0

func (r *RTPPacketReaderConcurent) SetRTPSession(rtpSess *RTPSession)

type RTPPacketWriter added in v0.2.0

type RTPPacketWriter struct {
	RTPSession *RTPSession
	Sess       *MediaSession
	Writer     RTPWriter

	// After each write this is set as packet.
	LastPacket rtp.Packet
	OnRTP      func(pkt *rtp.Packet)

	// This properties are read only or can be changed only after creating writer
	PayloadType uint8
	SSRC        uint32
	SampleRate  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 added in v0.2.0

func NewRTPPacketWriter(writer RTPWriter, codec Codec) *RTPPacketWriter

func NewRTPPacketWriterMedia added in v0.2.0

func NewRTPPacketWriterMedia(sess *MediaSession) *RTPPacketWriter

NewRTPPacketWriterMedia is left for backward compability. It does not add RTCP reporting RTPSession should be used for media quality reporting

func NewRTPPacketWriterSession added in v0.2.0

func NewRTPPacketWriterSession(sess *RTPSession) *RTPPacketWriter

RTP writer 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 (*RTPPacketWriter) Write added in v0.2.0

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 Has no capabilities (yet): - MTU UDP limit handling - Media clock rate of payload is consistent - Packet loss detection - RTCP generating

func (*RTPPacketWriter) WriteSamples added in v0.2.0

func (p *RTPPacketWriter) WriteSamples(payload []byte, clockRateTimestamp uint32, marker bool, payloadType uint8) (int, error)

type RTPPacketWriterConcurent added in v0.2.0

type RTPPacketWriterConcurent struct {
	*RTPPacketWriter
	// contains filtered or unexported fields
}

Experimental

RTPPacketWriterConcurent allows updating RTPSession on RTPWriter and more (in case of reestablish)

func (*RTPPacketWriterConcurent) SetRTPSession added in v0.2.0

func (w *RTPPacketWriterConcurent) SetRTPSession(rtpSess *RTPSession)

func (*RTPPacketWriterConcurent) SetRTPWriter added in v0.2.0

func (w *RTPPacketWriterConcurent) SetRTPWriter(rtpWriter *RTPPacketWriter)

func (*RTPPacketWriterConcurent) Write added in v0.2.0

func (w *RTPPacketWriterConcurent) Write(b []byte) (int, error)

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
	IntervalTotalPackets   uint16

	TotalPackets uint64

	// 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 RTPReader

type RTPReader interface {
	ReadRTP(buf []byte, p *rtp.Packet) error
}

type RTPReaderRaw added in v0.2.0

type RTPReaderRaw interface {
	ReadRTPRaw(buf []byte) (int, error)
}

type RTPSession

type RTPSession struct {
	// Keep pointers at top to reduce GC
	Sess *MediaSession

	// Experimental
	// this intercepts reading or writing rtcp packet. Allows manipulation
	OnReadRTCP  func(pkt rtcp.Packet, rtpStats RTPReadStats)
	OnWriteRTCP func(pkt rtcp.Packet, rtpStats RTPWriteStats)
	// contains filtered or unexported fields
}

RTP session is RTP ReadWriter with control (RTCP) reporting Session is identified by network address and port pair to which data should be sent and received Participant can be part of multiple rtp sessions. One for audio, one for media. So for different MediaSession (audio,video etc) different RTP session needs to be created TODO RTPSession can be different type: - unicast or multicase - replicated unicast (mixers audio) RTP session is attached to RTPReader and RTPWriter Now: - Designed for UNICAST sessions - Acts as RTP Reader Writer - Only makes sense for Reporting Quality mediaw Roadmap: - Can handle multiple SSRC from Reader - Multiple RTCP Recever Blocks

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 added in v0.2.0

func (s *RTPSession) MonitorBackground()

MonitorBackground is helper to keep monitoring in background

func (*RTPSession) ReadRTP

func (s *RTPSession) ReadRTP(b []byte, readPkt *rtp.Packet) error

func (*RTPSession) ReadRTPRaw added in v0.2.0

func (s *RTPSession) ReadRTPRaw(buf []byte) (int, error)

func (*RTPSession) WriteRTP

func (s *RTPSession) WriteRTP(pkt *rtp.Packet) error

func (*RTPSession) WriteRTPRaw added in v0.2.0

func (s *RTPSession) WriteRTPRaw(buf []byte) (int, error)

type RTPWriteStats

type RTPWriteStats struct {
	SSRC uint32

	// RTCP stats
	PacketsCount uint32
	OctetCount   uint32
	// contains filtered or unexported fields
}

Some of fields here are exported (as readonly) intentionally

type RTPWriter

type RTPWriter interface {
	WriteRTP(p *rtp.Packet) error
}

type RTPWriterRaw added in v0.2.0

type RTPWriterRaw interface {
	WriteRTPRaw(buf []byte) (int, error) // -> io.Writer
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL