sfu

package module
v0.0.0-...-3a52945 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2024 License: MIT Imports: 53 Imported by: 0

README

[!IMPORTANT]
This library still in very early development. The API might change in the future. We use it in production for inLive Hub project. We're a small team, so we can't guarantee that we can fix all issues. But we will try our best to fix it especially when it's related with our product. If you have any questions or find any issues, please write it to this repo Github issue. We will appreciate it.

inLive Hub SFU

This Golang package is an SFU library based on Pion WebRTC. It is designed to be used in the inLive Hub project, but it can also be used in other projects. The goal is to have a Golang SFU library that is portable but easy to extend.

Installation

This is a Go module, so you can install it by running this command in your app directory:

go get github.com/inlivedev/sfu

Features

  • Group call
  • Screen sharing
  • Perfect negotiation
  • Data channel - note: only room channel currenty available
  • Simulcast
  • Scalable Video Coding (SVC)
  • Voice activity detection
  • Room statistic

Components:

This SFU package has four components:

  1. Client, a WebRTC client as a relay client in the SFU.
  2. SFU, the SFU server.
  3. Room, a signaling controller between SFU and clients.
  4. Room Manager, a controller to manage multiple rooms

How to use

The one that you will interact with will be the room and the room manager. A server will at least have a single room manager. Before being able to run a group video call, you need to create a room with the room manager, then use that room to add clients to it. You can use any protocol as your signaling controller.

SFU <---> Room <---> REST/WebSocket/gRPC <---> browser/app
 |
 |
 \/
 Clients

See the example folder to see how to write a group video call app with this SFU package. The following section will explain in detail how to use this package.

Connect to the SFU

On the first connection to SFU, a client will do a WebRTC negotiation, exchanging Session Description Protocol(SDP) and ice candidates. The client will send an offer SDP to initiate the negotiation. The SFU will respond with an answer SDP. Then both will exchange the ice candidates.

The steps will be like this to initiate the negotiation with the client.

  1. Add a client first to the SFU by calling AddClient(clientID, sfu.DefaultClientOptions()) on the current room instance. The clientID must be a unique string. The client options can be customized, but the default should be enough.
  2. Once added, now we can access the relay client from the SFU through currentRoom.SFU.GetClient(clientID). The relay client is a WebRTC client on the SFU side that will be used to negotiate with the client.
  3. To start the negotiation you can pass the offer SDP from the client to client.Negotiate(offer) method. The method will return an answer SDP that you need to pass back to the client. As part of the negotiation, you need to pass the ice candidates from the client to client.AddICECandidate(candidate) method.
  4. You also need to pass the ice candidates from the relay client to the client. You can get the ice candidates from the relay client by listening to the client.OnICECandidate event. The event will be triggered when the relay client has a new ice candidate. You only need to send this ice candidate to the client.

Once you complete the five steps above, the connection should be established. See the example of how the connection is established here

Publish and subscribe tracks

When a client wants to publish a track to the SFU, usually the flow is like this:

  1. Get the media tracks from either the camera or the screen sharing. You can use getUserMedia to get the media tracks.
  2. Add the media tracks to the WebRTC PeerConnection instance. You can use addTrack to add the media tracks to the PeerConnection instance.
  3. This will add the tracks to SFU but won't be published until the client sets the track source type either media or screen.
  4. When the track is added to SFU, the client will trigger client.OnTrackAdded([]*tracks). We need to use this event to set the track source type by calling client.SetTracksSourceType(map[trackTypes string]TrackType)`
  5. When successful, this will trigger client.OnTrackAvailable([]*tracks) event on other clients.
  6. Use this event to subscribe to the tracks by calling client.SubscribeTracks(tracksReq []SubscribeTrackRequest) method. When successful, it will trigger peerConnection.OnTrack() event that we can use to attach the track to the HTML video element. Or instead of manually subscribing to each track, you can also use client.SubscribeAllTracks() method to subscribe to all available tracks. You only need to call it once, and all available tracks will automatically added to the PeerConnection instance.

See the client_test.go for more details on how to publish and subscribe to tracks.

Renegotiation

Usually, renegotiation will be needed when a new track is added or removed. The renegotiation can be initiated by the SFU if a new client joins the room and publishes a new track to the room. To broadcast the track to all clients, the SFU must renegotiate with each client to inform them about the new tracks.

Renegotiation from the SFU

To wait for the renegotiation process from SFU to make sure you receive a new track once published in a room, you can do this:

  1. When creating a new client after calling currentRoom.addClient() method, you can listen to the client.OnRenegotiation event. The event will be triggered when the SFU is trying to renegotiate with the client.
  2. Once you receive an offer from the SFU, you can pass the offer SDP to the client and get the answer to pass back to the SFU.
  3. The event client.OnRenegotiation must return an answer SDP received from the client, and it suggested having a timeout when waiting for the answer from the client. If the timeout is reached, you can return an empty SDP to the SFU.

See the example of how the renegotiation is handled here

Renegotiation from the client

The renegotiation also can be initiated by the client if the client is adding a new track, for example, by doing a screen sharing. Because both sides can initiate the renegotiation, there is a possibility that both sides are trying to renegotiate at the same time.

To prevent this, we need to check with the SFU relay client if it is allowed to do renegotiation from the client side by checking the client.IsAllowNegotiation() method. If it returns true, then we can start the renegotiation by calling client.Negotiate(offer) method. The same method that we used for the first negotiation. The SFU will respond with an SDP answer to the client. Make sure after you call client.IsAllowNegotiation() method, you also call client.Negotiate(offer) method to make sure the in-renegotiation state is processed by the SFU. If you do not call the following method, the SFU will think that the client is doing a renegotiation and won't initiate the renegotiation.

If the client.IsAllowNegotiation() is returned false, it means the SFU is currently trying to renegotiate with the client. So the client should wait until the SFU is done renegotiating with the client. In the browser, you can listen to the onnegotiationneeded event to know when the SFU is done renegotiating with the client.

Leave the room

If a client wants to leave a room or disconnect from the SFU. You can close the PeerConnection instance on the client side. The SFU will detect that the client is closed and will remove the client from the room.

Logging

This library is using Glog for logging. You can set the log level by setting the -flag stderrthreshold=warning when running an application from the command line. You can control it also from your app using the flag package. The default log level is info. The available log levels are info, warning, error, fatal, and panic. You can read more about Glog here

To set the log printing to stderr instead of a file, you can set the -flag logtostderr=true flag variable to true. The default is false.

Licence

MIT License - see LICENSE for the full text

Documentation

Index

Constants

View Source
const (
	ClientStateNew     = 0
	ClientStateActive  = 1
	ClientStateRestart = 2
	ClientStateEnded   = 3

	ClientTypePeer       = "peer"
	ClientTypeUpBridge   = "upbridge"
	ClientTypeDownBridge = "downbridge"

	QualityAudioRed = 11
	QualityAudio    = 10
	QualityHigh     = 9
	QualityHighMid  = 8
	QualityHighLow  = 7
	QualityMid      = 6
	QualityMidMid   = 5
	QualityMidLow   = 4
	QualityLow      = 3
	QualityLowMid   = 2
	QualityLowLow   = 1
	QualityNone     = 0
)
View Source
const (
	KEEPLAYER      = OperationType(0)
	SCALEDOWNLAYER = OperationType(1)
	SCALEUPLAYER   = OperationType(2)
)
View Source
const (
	StateRoomOpen       = "open"
	StateRoomClosed     = "closed"
	EventRoomClosed     = "room_closed"
	EventRoomClientLeft = "room_client_left"
)
View Source
const (
	TrackTypeMedia  = "media"
	TrackTypeScreen = "screen"
)
View Source
const (
	DefaultReceiveBitrate = 1_500_000
)
View Source
const (
	SdesRepairRTPStreamIDURI = "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"
)

Variables

View Source
var (
	ErrAlreadyClaimed          = errors.New("bwcontroller: already claimed")
	ErrorInsufficientBandwidth = errors.New("bwcontroller: bandwidth is insufficient")
)
View Source
var (
	ErrNegotiationIsNotRequested = errors.New("client: error negotiation is called before requested")
	ErrRenegotiationCallback     = errors.New("client: error renegotiation callback is not set")
	ErrClientStoped              = errors.New("client: error client already stopped")
)
View Source
var (
	ErrIncompleteRedHeader = errors.New("util: incomplete RED header")
	ErrIncompleteRedBlock  = errors.New("util: incomplete RED block")
)
View Source
var (
	H264KeyFrame2x2SPS = []byte{
		0x67, 0x42, 0xc0, 0x1f, 0x0f, 0xd9, 0x1f, 0x88,
		0x88, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
		0x00, 0x03, 0x00, 0xc8, 0x3c, 0x60, 0xc9, 0x20,
	}
	H264KeyFrame2x2PPS = []byte{
		0x68, 0x87, 0xcb, 0x83, 0xcb, 0x20,
	}
	H264KeyFrame2x2IDR = []byte{
		0x65, 0x88, 0x84, 0x0a, 0xf2, 0x62, 0x80, 0x00,
		0xa7, 0xbe,
	}
	H264KeyFrame2x2 = [][]byte{H264KeyFrame2x2SPS, H264KeyFrame2x2PPS, H264KeyFrame2x2IDR}

	OpusSilenceFrame = []byte{
		0xf8, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	}
)
View Source
var (
	ErrClientNotFound = errors.New("client not found")
	ErrClientExists   = errors.New("client already exists")

	ErrRoomIsClosed   = errors.New("room is closed")
	ErrRoomIsNotEmpty = errors.New("room is not empty")
	ErrDecodingData   = errors.New("error decoding data")
	ErrEncodingData   = errors.New("error encoding data")
	ErrNotFound       = errors.New("not found")
)
View Source
var (
	ErrRoomNotFound             = errors.New("manager: room not found")
	ErrRoomAlreadyExists        = errors.New("manager: room already exists")
	ErrRemoteRoomConnectTimeout = errors.New("manager: timeout connecting to remote room")

	RoomTypeLocal  = "local"
	RoomTypeRemote = "remote"
)
View Source
var (
	ErrPacketTooLate   = errors.New("packetbuffers: packet is too late")
	ErrPacketDuplicate = errors.New("packetbuffers: packet is duplicate")
)
View Source
var (
	ErrCantDecide = errors.New("can't decide if upscale or downscale the layer")
	ErrDuplicate  = errors.New("packet sequence already exists in the cache")
)
View Source
var (
	ErrTrackExists      = errors.New("client: error track already exists")
	ErrTrackIsNotExists = errors.New("client: error track is not exists")
)
View Source
var DefaultQualityPresets = map[QualityLevel]QualityPreset{
	QualityHigh: QualityPreset{
		SID: 2,
		TID: 2,
	},
	QualityHighMid: QualityPreset{
		SID: 2,
		TID: 1,
	},
	QualityHighLow: QualityPreset{
		SID: 2,
		TID: 0,
	},
	QualityMid: QualityPreset{
		SID: 1,
		TID: 2,
	},
	QualityMidMid: QualityPreset{
		SID: 1,
		TID: 1,
	},
	QualityMidLow: QualityPreset{
		SID: 1,
		TID: 0,
	},
	QualityLow: QualityPreset{
		SID: 0,
		TID: 2,
	},
	QualityLowMid: QualityPreset{
		SID: 0,
		TID: 1,
	},
	QualityLowLow: QualityPreset{
		SID: 0,
		TID: 0,
	},
	QualityNone: QualityPreset{
		SID: 0,
		TID: 0,
	},
}
View Source
var (
	ErrCLientStatsNotFound = errors.New("client stats not found")
)
View Source
var (
	ErrDataChannelExists = errors.New("error: data channel already exists")
)
View Source
var (
	ErrMetaNotFound = errors.New("meta: metadata not found")
)

Functions

func AddSimulcastVideoTracks

func AddSimulcastVideoTracks(ctx, iceConnectedCtx context.Context, pc *webrtc.PeerConnection, trackID, streamID string) error

func CountTracks

func CountTracks(sdp string) int

func CreatePeerPair

func CreatePeerPair(ctx context.Context, log logging.LeveledLogger, room *Room, iceServers []webrtc.ICEServer, peerName string, loop, isSimulcast bool, isIceTrickle bool) (*PC, *Client, stats.Getter, chan bool)

func FlattenErrors

func FlattenErrors(errs []error) error

func GenerateID

func GenerateID(length int) string

func GenerateSecureToken

func GenerateSecureToken() string

func GetLocalIp

func GetLocalIp() (net.IP, error)

func GetMediaEngine

func GetMediaEngine() *webrtc.MediaEngine

func GetReceiverStats

func GetReceiverStats(pc *webrtc.PeerConnection, statsGetter stats.Getter) map[webrtc.SSRC]stats.Stats

func GetSenderStats

func GetSenderStats(pc *webrtc.PeerConnection, statsGetter stats.Getter) map[webrtc.SSRC]stats.Stats

func GetStaticAudioTrack

func GetStaticAudioTrack(ctx, iceConnectedCtx context.Context, trackID, streamID string, loop bool) (*webrtc.TrackLocalStaticSample, chan bool)

func GetStaticTracks

func GetStaticTracks(ctx, iceConnectedCtx context.Context, streamID string, loop bool) ([]*webrtc.TrackLocalStaticSample, chan bool)

func GetStaticVideoTrack

func GetStaticVideoTrack(ctx, iceConnectedCtx context.Context, trackID, streamID string, loop bool, quality string) (*webrtc.TrackLocalStaticSample, chan bool)

func GetUfragAndPass

func GetUfragAndPass(sdp string) (ufrag, pass string)

func IsKeyframe

func IsKeyframe(codec string, packet *rtp.Packet) bool

func IsRTPPacketLate

func IsRTPPacketLate(packetSeqNum uint16, lastSeqNum uint16) bool

func Keyframe

func Keyframe(codec string, packet *rtp.Packet) (bool, bool)

This keyframe related code is taken from https://github.com/jech/galene/blob/cc2ed144843ef5ebc4353b7096708355cab3b992/codecs/codecs.go#L17 all credits belongs to Juliusz Chroboczek @jech the creator of Galene

Keyframe determines if packet is the start of a keyframe. It returns (true, true) if that is the case, (false, true) if that is definitely not the case, and (false, false) if the information cannot be determined.

func KeyframeDimensions

func KeyframeDimensions(codec string, packet *rtp.Packet) (uint32, uint32)

func LoadVp9Track

func LoadVp9Track(ctx context.Context, log logging.LeveledLogger, pc *webrtc.PeerConnection, videoFileName string, loop bool) *webrtc.RTPSender

func PayloaderForCodec

func PayloaderForCodec(codec webrtc.RTPCodecCapability) (rtp.Payloader, error)

reuse from pion media engine and media sample

func RegisterCodecs

func RegisterCodecs(m *webrtc.MediaEngine, codecs []string) error

func RegisterDefaultCodecs

func RegisterDefaultCodecs(m *webrtc.MediaEngine) error

func RegisterSimulcastHeaderExtensions

func RegisterSimulcastHeaderExtensions(m *webrtc.MediaEngine, codecType webrtc.RTPCodecType)

func SendMediaSamples

func SendMediaSamples(p rtp.Packetizer, sequencer rtp.Sequencer, localRTP *webrtc.TrackLocalStaticRTP, sample media.Sample) error

func SetPeerConnectionTracks

func SetPeerConnectionTracks(ctx context.Context, peerConnection *webrtc.PeerConnection, tracks []*webrtc.TrackLocalStaticSample)

func StartStunServer

func StartStunServer(ctx context.Context, publicIP string) *turn.Server

func StartTurnServer

func StartTurnServer(ctx context.Context, publicIP string) *turn.Server

func ThousandSeparator

func ThousandSeparator(n int) string

Types

type AudioTrack

type AudioTrack struct {
	*Track
	// contains filtered or unexported fields
}

func (*AudioTrack) OnVoiceDetected

func (t *AudioTrack) OnVoiceDetected(callback func(pkts []voiceactivedetector.VoicePacketData))

func (*AudioTrack) SetVAD

type BitrateConfigs

type BitrateConfigs struct {
	AudioRed         uint32 `json:"audio_red" example:"75000"`
	Audio            uint32 `json:"audio" example:"48000"`
	Video            uint32 `json:"video" example:"1200000"`
	VideoHigh        uint32 `json:"video_high" example:"1200000"`
	VideoHighPixels  uint32 `json:"video_high_pixels" example:"921600"`
	VideoMid         uint32 `json:"video_mid" example:"500000"`
	VideoMidPixels   uint32 `json:"video_mid_pixels" example:"259200"`
	VideoLow         uint32 `json:"video_low" example:"150000"`
	VideoLowPixels   uint32 `json:"video_low_pixels" example:"64800"`
	InitialBandwidth uint32 `json:"initial_bandwidth" example:"1000000"`
}

BitrateConfigs is the configuration for the bitrate that will be used for adaptive bitrates controller The paramenter is in bps (bit per second) for non pixels parameters. For pixels parameters, it is total pixels (width * height) of the video. High, Mid, and Low are the references for bitrate controller to decide the max bitrate to send to the client.

func DefaultBitrates

func DefaultBitrates() BitrateConfigs

type Cache

type Cache struct {
	SeqNum    uint16
	Timestamp uint32
	BaseSeq   uint16
	// packet TID
	PTID uint8
	// packet SID
	PSID uint8
	// stream TID
	TID uint8
	// stream SID
	SID uint8
}

type Client

type Client struct {
	// contains filtered or unexported fields
}

func CreateDataPair

func CreateDataPair(ctx context.Context, log logging.LeveledLogger, room *Room, iceServers []webrtc.ICEServer, peerName string, onDataChannel func(d *webrtc.DataChannel)) (*webrtc.PeerConnection, *Client, stats.Getter, chan webrtc.PeerConnectionState)

func NewClient

func NewClient(s *SFU, id string, name string, peerConnectionConfig webrtc.Configuration, opts ClientOptions) *Client

func (*Client) AddICECandidate

func (c *Client) AddICECandidate(candidate webrtc.ICECandidateInit) error

func (*Client) ClientTracks

func (c *Client) ClientTracks() map[string]iClientTrack

func (*Client) CompleteNegotiation

func (c *Client) CompleteNegotiation(answer webrtc.SessionDescription)

func (*Client) Context

func (c *Client) Context() context.Context

func (*Client) EnableDebug

func (c *Client) EnableDebug()

func (*Client) End

func (c *Client) End() error

End the client connection and clean up the resources.

func (*Client) GetEstimatedBandwidth

func (c *Client) GetEstimatedBandwidth() uint32

GetEstimatedBandwidth returns the estimated bandwidth in bits per second based on Google Congestion Controller estimation. If the congestion controller is not enabled, it will return the initial bandwidth. If the receiving bandwidth is not 0, it will return the smallest value between the estimated bandwidth and the receiving bandwidth.

func (*Client) ID

func (c *Client) ID() string

func (*Client) InitNegotiation

func (c *Client) InitNegotiation() *webrtc.SessionDescription

Init and Complete negotiation is used for bridging the room between servers

func (*Client) IsAllowNegotiation

func (c *Client) IsAllowNegotiation() bool

ask if allowed for remote negotiation is required before call negotiation to make sure there is no racing condition of negotiation between local and remote clients. return false means the negotiation is in process, the requester must have a mechanism to repeat the request once it's done. requesting this must be followed by calling Negotate() to make sure the state is completed. Failed on called Negotiate() will cause the client to be in inconsistent state.

func (*Client) IsBridge

func (c *Client) IsBridge() bool

func (*Client) IsDebugEnabled

func (c *Client) IsDebugEnabled() bool

func (*Client) IsVADEnabled

func (c *Client) IsVADEnabled() bool

func (*Client) Name

func (c *Client) Name() string

func (*Client) Negotiate

func (c *Client) Negotiate(offer webrtc.SessionDescription) (*webrtc.SessionDescription, error)

func (*Client) OnAllowedRemoteRenegotiation

func (c *Client) OnAllowedRemoteRenegotiation(callback func())

OnAllowedRemoteRenegotiation event is called when the SFU is done with the renegotiation and ready to receive the renegotiation from the client. Use this event to trigger the client to do renegotiation if needed.

func (*Client) OnConnectionStateChanged

func (c *Client) OnConnectionStateChanged(callback func(webrtc.PeerConnectionState))

OnConnectionStateChanged event is called when the SFU connection state is changed. The callback will receive the connection state as the new state.

func (*Client) OnIceCandidate

func (c *Client) OnIceCandidate(callback func(context.Context, *webrtc.ICECandidate))

OnTracksAvailable event is called when the SFU has ice candidate that need to pass to the client. This event will triggered during negotiation process to exchanges ice candidates between SFU and client. The client can also pass the ice candidate to the SFU using `client.AddICECandidate()` method.

func (*Client) OnJoined

func (c *Client) OnJoined(callback func())

OnJoined event is called when the client is joined to the room. This doesn't mean that the client's tracks are already published to the room. This event can be use to track number of clients in the room.

func (*Client) OnLeft

func (c *Client) OnLeft(callback func())

OnLeft event is called when the client is left from the room. This event can be use to track number of clients in the room.

func (*Client) OnNetworkConditionChanged

func (c *Client) OnNetworkConditionChanged(callback func(networkmonitor.NetworkConditionType))

func (*Client) OnRenegotiation

func (c *Client) OnRenegotiation(callback func(context.Context, webrtc.SessionDescription) (webrtc.SessionDescription, error))

OnRenegotiation event is called when the SFU is trying to renegotiate with the client. The callback will receive the SDP offer from the SFU that must be use to create the SDP answer from the client. The SDP answer then can be passed back to the SFU using `client.CompleteNegotiation()` method.

func (*Client) OnTrackRemoved

func (c *Client) OnTrackRemoved(callback func(sourceType string, track *webrtc.TrackLocalStaticRTP))

OnTrackRemoved event is called when the client's track is removed from the room. Usually this triggered when the client is disconnected from the room or a track is unpublished from the client.

func (*Client) OnTracksAdded

func (c *Client) OnTracksAdded(callback func(addedTracks []ITrack))

OnTrackAdded event is to confirmed the source type of the pending published tracks. If the event is not listened, the pending published tracks will be ignored and not published to other clients. Once received, respond with `client.SetTracksSourceType()“ to confirm the source type of the pending published tracks

func (*Client) OnTracksAvailable

func (c *Client) OnTracksAvailable(callback func([]ITrack))

OnTracksAvailable event is called when the SFU is trying to publish new tracks to the client. The client then can subscribe to the tracks by calling `client.SubscribeTracks()` method. The callback will receive the list of tracks from other clients that are available to subscribe.

func (*Client) OnTracksReady

func (c *Client) OnTracksReady(callback func([]ITrack))

OnTracksReady event is called when the client's tracks are use from the client This can be use to hook a processing like transcription/video processing to client published tracks

func (*Client) OnVoiceReceivedDetected

func (c *Client) OnVoiceReceivedDetected(callback func(activity voiceactivedetector.VoiceActivity))

func (*Client) OnVoiceSentDetected

func (c *Client) OnVoiceSentDetected(callback func(activity voiceactivedetector.VoiceActivity))

OnVoiceDetected event is called when the SFU is detecting voice activity in the room. The callback will receive the voice activity data that can be use for visual indicator of current speaker.

func (*Client) PeerConnection

func (c *Client) PeerConnection() *PeerConnection

func (*Client) PublishedTracks

func (c *Client) PublishedTracks() []ITrack

func (*Client) SFU

func (c *Client) SFU() *SFU

func (*Client) SetName

func (c *Client) SetName(name string)

SetName update the name of the client, that previously set on create client The name then later can use by call client.Name() method

func (*Client) SetQuality

func (c *Client) SetQuality(quality QualityLevel)

SetQuality method is to set the maximum quality of the video that will be sent to the client. This is for bandwidth efficiency purpose and use when the video is rendered in smaller size than the original size.

func (*Client) SetReceivingBandwidthLimit

func (c *Client) SetReceivingBandwidthLimit(bandwidth uint32)

SetReceivingBandwidthLimit will cap the receiving bandwidth and will overide the bandwidth estimation if the value is lower than the estimated bandwidth. This is useful to test how the SFU will behave when the bandwidth is limited

func (*Client) SetTracksSourceType

func (c *Client) SetTracksSourceType(trackTypes map[string]TrackType)

SetTracksSourceType set the source type of the pending published tracks. This function must be called after receiving OnTracksAdded event. The source type can be "media" or "screen" Calling this method will trigger `client.OnTracksAvailable` event to other clients. The other clients then can subscribe the tracks using `client.SubscribeTracks()` method.

func (*Client) Stats

func (c *Client) Stats() ClientTrackStats

TODO: fix the panic nil here when the client is ended

func (*Client) SubscribeTracks

func (c *Client) SubscribeTracks(req []SubscribeTrackRequest) error

SubscribeTracks subscribe tracks from other clients that are published to this client The client must listen for `client.OnTracksAvailable` to know if a new track is available to subscribe. Calling subscribe tracks will trigger the SFU renegotiation with the client.

func (*Client) Tracks

func (c *Client) Tracks() []ITrack

func (*Client) Type

func (c *Client) Type() string

func (*Client) UpdatePublisherBandwidth

func (c *Client) UpdatePublisherBandwidth(bitrate uint32)

This should get from the publisher client using RTCIceCandidatePairStats.availableOutgoingBitrate from client stats. It should be done through DataChannel so it won't required additional implementation on API endpoints where this SFU is used.

type ClientOptions

type ClientOptions struct {
	IceTrickle           bool          `json:"ice_trickle"`
	IdleTimeout          time.Duration `json:"idle_timeout"`
	Type                 string        `json:"type"`
	EnableVoiceDetection bool          `json:"enable_voice_detection"`
	EnablePlayoutDelay   bool          `json:"enable_playout_delay"`
	EnableOpusDTX        bool          `json:"enable_opus_dtx"`
	EnableOpusInbandFEC  bool          `json:"enable_opus_inband_fec"`
	// Configure the minimum playout delay that will be used by the client
	// Recommendation:
	// 0 ms: Certain gaming scenarios (likely without audio) where we will want to play the frame as soon as possible. Also, for remote desktop without audio where rendering a frame asap makes sense
	// 100/150/200 ms: These could be the max target latency for interactive streaming use cases depending on the actual application (gaming, remoting with audio, interactive scenarios)
	// 400 ms: Application that want to ensure a network glitch has very little chance of causing a freeze can start with a minimum delay target that is high enough to deal with network issues. Video streaming is one example.
	MinPlayoutDelay uint16 `json:"min_playout_delay"`
	// Configure the minimum playout delay that will be used by the client
	// Recommendation:
	// 0 ms: Certain gaming scenarios (likely without audio) where we will want to play the frame as soon as possible. Also, for remote desktop without audio where rendering a frame asap makes sense
	// 100/150/200 ms: These could be the max target latency for interactive streaming use cases depending on the actual application (gaming, remoting with audio, interactive scenarios)
	// 400 ms: Application that want to ensure a network glitch has very little chance of causing a freeze can start with a minimum delay target that is high enough to deal with network issues. Video streaming is one example.
	MaxPlayoutDelay     uint16        `json:"max_playout_delay"`
	JitterBufferMinWait time.Duration `json:"jitter_buffer_min_wait"`
	JitterBufferMaxWait time.Duration `json:"jitter_buffer_max_wait"`
	// On unstable network, the packets can be arrived unordered which may affected the nack and packet loss counts, set this to true to allow the SFU to handle reordered packet
	ReorderPackets bool `json:"reorder_packets"`
	Log            logging.LeveledLogger
	// contains filtered or unexported fields
}

func DefaultClientOptions

func DefaultClientOptions() ClientOptions

type ClientState

type ClientState int

type ClientStats

type ClientStats struct {
	Client *Client
	*TrackStats
	// contains filtered or unexported fields
}

func (*ClientStats) GetReceiver

func (c *ClientStats) GetReceiver(id, rid string) (stats.Stats, error)

func (*ClientStats) GetReceiverBitrate

func (c *ClientStats) GetReceiverBitrate(id, rid string) (uint32, error)

func (*ClientStats) GetSender

func (c *ClientStats) GetSender(id string) (stats.Stats, error)

func (*ClientStats) GetSenderBitrate

func (c *ClientStats) GetSenderBitrate(id string) (uint32, error)

func (*ClientStats) Receivers

func (c *ClientStats) Receivers() map[string]stats.Stats

func (*ClientStats) Senders

func (c *ClientStats) Senders() map[string]stats.Stats

func (*ClientStats) SetReceiver

func (c *ClientStats) SetReceiver(id, rid string, stats stats.Stats)

func (*ClientStats) SetSender

func (c *ClientStats) SetSender(id string, stats stats.Stats)

func (*ClientStats) UpdateVoiceActivity

func (c *ClientStats) UpdateVoiceActivity(ts uint32, clockRate uint32)

UpdateVoiceActivity updates voice activity duration 0 timestamp means ended

func (*ClientStats) VoiceActivity

func (c *ClientStats) VoiceActivity() time.Duration

type ClientTrackStats

type ClientTrackStats struct {
	ID                       string               `json:"id"`
	Name                     string               `json:"name"`
	PublisherBandwidth       uint32               `json:"publisher_bandwidth"`
	ConsumerBandwidth        uint32               `json:"consumer_bandwidth"`
	CurrentConsumerBitrate   uint32               `json:"current_bitrate"`
	CurrentPublishLimitation string               `json:"current_publish_limitation"`
	Sents                    []TrackSentStats     `json:"sent_track_stats"`
	Receives                 []TrackReceivedStats `json:"received_track_stats"`
	// in milliseconds
	VoiceActivityDurationMS uint32 `json:"voice_activity_duration_ms"`
}

type ClientType

type ClientType string

type Data

type Data struct {
	FromID string      `json:"from_id"`
	ToID   string      `json:"to_id"`
	SentAt time.Time   `json:"sent_at"`
	Data   interface{} `json:"data"`
}

type DataChannelList

type DataChannelList struct {
	// contains filtered or unexported fields
}

func NewDataChannelList

func NewDataChannelList(ctx context.Context) *DataChannelList

func (*DataChannelList) Add

func (d *DataChannelList) Add(dc *webrtc.DataChannel)

func (*DataChannelList) Clear

func (d *DataChannelList) Clear()

func (*DataChannelList) Get

func (d *DataChannelList) Get(label string) *webrtc.DataChannel

func (*DataChannelList) Remove

func (d *DataChannelList) Remove(dc *webrtc.DataChannel)

type DataChannelOptions

type DataChannelOptions struct {
	Ordered   bool
	ClientIDs []string // empty means all clients
}

func DefaultDataChannelOptions

func DefaultDataChannelOptions() DataChannelOptions

type Event

type Event struct {
	Type string
	Time time.Time
	Data map[string]interface{}
}

type IExtension

type IExtension interface {
	// This can be use for authentication before a client add to a room
	OnBeforeClientAdded(room *Room, clientID string) error
	OnClientAdded(room *Room, client *Client)
	OnClientRemoved(room *Room, client *Client)
}

type IManagerExtension

type IManagerExtension interface {
	// only the first extension that returns a room or an error will be used, once a room or an error is returned, the rest of the extensions will be ignored
	OnGetRoom(manager *Manager, roomID string) (*Room, error)
	// this can be use for authentication before a room is created
	OnBeforeNewRoom(id, name, roomType string) error
	OnNewRoom(manager *Manager, room *Room)
	OnRoomClosed(manager *Manager, room *Room)
}

type IQualityPreset

type IQualityPreset interface {
	GetSID() uint8
	GetTID() uint8
}

type IRemoteTrack

type IRemoteTrack interface {
	ID() string
	RID() string
	PayloadType() webrtc.PayloadType
	Kind() webrtc.RTPCodecType
	StreamID() string
	SSRC() webrtc.SSRC
	Msid() string
	Codec() webrtc.RTPCodecParameters
	Read(b []byte) (n int, attributes interceptor.Attributes, err error)
	ReadRTP() (*rtp.Packet, interceptor.Attributes, error)
	SetReadDeadline(deadline time.Time) error
}

func NewTrackRelay

func NewTrackRelay(id, streamid, rid string, kind webrtc.RTPCodecType, ssrc webrtc.SSRC, mimeType string, rtpChan chan *rtp.Packet) IRemoteTrack

type ITrack

type ITrack interface {
	ID() string
	StreamID() string
	ClientID() string
	IsSimulcast() bool
	IsScaleable() bool
	IsProcessed() bool
	SetSourceType(TrackType)
	SourceType() TrackType
	SetAsProcessed()
	OnRead(func(interceptor.Attributes, *rtp.Packet, QualityLevel))
	IsScreen() bool
	IsRelay() bool
	Kind() webrtc.RTPCodecType
	MimeType() string
	TotalTracks() int
	Context() context.Context
	Relay(func(webrtc.SSRC, interceptor.Attributes, *rtp.Packet))
	PayloadType() webrtc.PayloadType
	OnEnded(func())
}

type InternalDataVAD

type InternalDataVAD struct {
	Type string                            `json:"type"`
	Data voiceactivedetector.VoiceActivity `json:"data"`
}

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager is a struct that manages all the rooms

func NewManager

func NewManager(ctx context.Context, name string, options Options) *Manager

func (*Manager) AddExtension

func (m *Manager) AddExtension(extension IManagerExtension)

func (*Manager) Close

func (m *Manager) Close()

Close will close all room and canceling the context

func (*Manager) CloseRoom

func (m *Manager) CloseRoom(id string) error

CloseRoom will stop all clients in the room and close it. This is a shortcut to find a room with id and close it.

func (*Manager) Context

func (m *Manager) Context() context.Context

func (*Manager) CreateRoomID

func (m *Manager) CreateRoomID() string

func (*Manager) GetRoom

func (m *Manager) GetRoom(id string) (*Room, error)

func (*Manager) Log

func (m *Manager) Log() logging.LeveledLogger

func (*Manager) Name

func (m *Manager) Name() string

func (*Manager) NewRoom

func (m *Manager) NewRoom(id, name, roomType string, opts RoomOptions) (*Room, error)

func (*Manager) RoomsCount

func (m *Manager) RoomsCount() int

type Metadata

type Metadata struct {
	// contains filtered or unexported fields
}

func NewMetadata

func NewMetadata() *Metadata

func (*Metadata) Delete

func (m *Metadata) Delete(key string) error

func (*Metadata) ForEach

func (m *Metadata) ForEach(f func(key string, value interface{}))

func (*Metadata) Get

func (m *Metadata) Get(key string) (interface{}, error)

func (*Metadata) OnChanged

func (m *Metadata) OnChanged(f func(key string, value interface{})) *OnMetaChangedCallback

OnChanged registers a callback to be called when a metadata is changed Make sure OnMetaChangedSubscription.Unsubscribe() is called when the callback is no longer needed

func (*Metadata) Set

func (m *Metadata) Set(key string, value interface{})

type OnMetaChangedCallback

type OnMetaChangedCallback struct {
	// contains filtered or unexported fields
}

func (*OnMetaChangedCallback) Remove

func (s *OnMetaChangedCallback) Remove()

Unsubscribe removes the callback from the metadata Make sure to call the method once the callback is no longer needed

type OperationType

type OperationType uint8

type Options

type Options struct {
	EnableBridging           bool
	EnableBandwidthEstimator bool
	IceServers               []webrtc.ICEServer
	MinPlayoutDelay          uint16
	MaxPlayoutDelay          uint16
	// SettingEngine is used to configure the WebRTC engine
	// Use this to configure use of enable/disable mDNS, network types, use single port mux, etc.
	SettingEngine *webrtc.SettingEngine
}

func DefaultOptions

func DefaultOptions() Options

type PC

type PC struct {
	Mu                *sync.Mutex
	PeerConnection    *webrtc.PeerConnection
	IsInRenegotiation bool
}

type Packet

type Packet struct {
	Packet *rtppool.RetainablePacket
	// contains filtered or unexported fields
}

type PacketBuffers

type PacketBuffers struct {
	// contains filtered or unexported fields
}

buffer ring for cached packets

func NewPacketBuffers

func NewPacketBuffers(ctx context.Context, minLatency, maxLatency time.Duration, dynamicLatency bool, log logging.LeveledLogger) *PacketBuffers

func (*PacketBuffers) Add

func (*PacketBuffers) Clear

func (p *PacketBuffers) Clear()

func (*PacketBuffers) Close

func (p *PacketBuffers) Close()

func (*PacketBuffers) Flush

func (p *PacketBuffers) Flush() []*Packet

func (*PacketBuffers) Initiated

func (p *PacketBuffers) Initiated() bool

func (*PacketBuffers) Last

func (p *PacketBuffers) Last() *Packet

func (*PacketBuffers) Len

func (p *PacketBuffers) Len() int

func (*PacketBuffers) MaxLatency

func (p *PacketBuffers) MaxLatency() time.Duration

func (*PacketBuffers) MinLatency

func (p *PacketBuffers) MinLatency() time.Duration

func (*PacketBuffers) Pop

func (p *PacketBuffers) Pop() *Packet

func (*PacketBuffers) WaitAvailablePacket

func (p *PacketBuffers) WaitAvailablePacket()

type PeerConnection

type PeerConnection struct {
	// contains filtered or unexported fields
}

func (*PeerConnection) AddTrack

func (p *PeerConnection) AddTrack(track *webrtc.TrackLocalStaticRTP) (*webrtc.RTPSender, error)

func (*PeerConnection) Close

func (p *PeerConnection) Close() error

func (*PeerConnection) PC

func (p *PeerConnection) PC() *webrtc.PeerConnection

func (*PeerConnection) RemoveTrack

func (p *PeerConnection) RemoveTrack(sender *webrtc.RTPSender) error

type PublishedTrack

type PublishedTrack struct {
	ClientID string
	Track    webrtc.TrackLocal
}

type QualityLevel

type QualityLevel uint32

func DefaultQualityLevels

func DefaultQualityLevels() []QualityLevel

func RIDToQuality

func RIDToQuality(RID string) QualityLevel

func Uint32ToQualityLevel

func Uint32ToQualityLevel(quality uint32) QualityLevel

type QualityPreset

type QualityPreset struct {
	SID uint8 `json:"sid" example:"2"`
	TID uint8 `json:"tid" example:"2"`
}

func (QualityPreset) GetSID

func (q QualityPreset) GetSID() uint8

func (QualityPreset) GetTID

func (q QualityPreset) GetTID() uint8

type QualityPresets

type QualityPresets struct {
	High    QualityPreset `json:"high"`
	HighMid QualityPreset `json:"highmid"`
	HighLow QualityPreset `json:"highlow"`
	Mid     QualityPreset `json:"mid"`
	MidMid  QualityPreset `json:"midmid"`
	MidLow  QualityPreset `json:"midlow"`
	Low     QualityPreset `json:"low"`
	LowMid  QualityPreset `json:"lowmid"`
	LowLow  QualityPreset `json:"lowlow"`
}

type RelayTrack

type RelayTrack struct {
	// contains filtered or unexported fields
}

TrackRemote represents a single inbound source of media

func (*RelayTrack) Codec

func (t *RelayTrack) Codec() webrtc.RTPCodecParameters

Codec gets the Codec of the track

func (*RelayTrack) ID

func (t *RelayTrack) ID() string

ID is the unique identifier for this Track. This should be unique for the stream, but doesn't have to globally unique. A common example would be 'audio' or 'video' and StreamID would be 'desktop' or 'webcam'

func (*RelayTrack) IsRelay

func (t *RelayTrack) IsRelay() bool

IsRelay returns true if this track is a relay track

func (*RelayTrack) Kind

func (t *RelayTrack) Kind() webrtc.RTPCodecType

Kind gets the Kind of the track

func (*RelayTrack) Msid

func (t *RelayTrack) Msid() string

Msid gets the Msid of the track

func (*RelayTrack) PayloadType

func (t *RelayTrack) PayloadType() webrtc.PayloadType

PayloadType gets the PayloadType of the track

func (*RelayTrack) RID

func (t *RelayTrack) RID() string

RID gets the RTP Stream ID of this Track With Simulcast you will have multiple tracks with the same ID, but different RID values. In many cases a TrackRemote will not have an RID, so it is important to assert it is non-zero

func (*RelayTrack) Read

func (t *RelayTrack) Read(b []byte) (n int, attributes interceptor.Attributes, err error)

Read reads data from the track.

func (*RelayTrack) ReadRTP

func (t *RelayTrack) ReadRTP() (*rtp.Packet, interceptor.Attributes, error)

ReadRTP is a convenience method that wraps Read and unmarshals for you.

func (*RelayTrack) SSRC

func (t *RelayTrack) SSRC() webrtc.SSRC

SSRC gets the SSRC of the track

func (*RelayTrack) SetReadDeadline

func (t *RelayTrack) SetReadDeadline(deadline time.Time) error

SetReadDeadline sets the max amount of time the RTP stream will block before returning. 0 is forever.

func (*RelayTrack) StreamID

func (t *RelayTrack) StreamID() string

StreamID is the group this track belongs too. This must be unique

type Room

type Room struct {
	RenegotiationChan map[string]chan bool

	OnEvent func(event Event)
	// contains filtered or unexported fields
}

func (*Room) AddClient

func (r *Room) AddClient(id, name string, opts ClientOptions) (*Client, error)

func (*Room) AddExtension

func (r *Room) AddExtension(extension IExtension)

func (*Room) BitrateConfigs

func (r *Room) BitrateConfigs() BitrateConfigs

BitrateConfigs return the current bitrate configuration that used in bitrate controller Client should use this to configure the bitrate when publishing media tracks Inconsistent bitrate configuration between client and server will result missed bitrate calculation and could affecting packet loss and media quality

func (*Room) Close

func (r *Room) Close() error

Close the room and stop all clients. All connected clients will stopped and removed from the room. All clients will get `connectionstateevent` with `closed` state. https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/connectionstatechange_event

func (*Room) CodecPreferences

func (r *Room) CodecPreferences() []string

CodecPreferences return the current codec preferences that used in SFU Client should use this to configure the used codecs when publishing media tracks Inconsistent codec preferences between client and server can make the SFU cannot handle the codec properly

func (*Room) Context

func (r *Room) Context() context.Context

func (*Room) CreateClientID

func (r *Room) CreateClientID() string

Generate a unique client ID for this room

func (*Room) CreateDataChannel

func (r *Room) CreateDataChannel(label string, opts DataChannelOptions) error

func (*Room) ID

func (r *Room) ID() string

func (*Room) Kind

func (r *Room) Kind() string

func (*Room) Meta

func (r *Room) Meta() *Metadata

func (*Room) Name

func (r *Room) Name() string

func (*Room) OnClientJoined

func (r *Room) OnClientJoined(callback func(client *Client))

func (*Room) OnClientLeft

func (r *Room) OnClientLeft(callback func(client *Client))

Use this to get notified when a client is stopped and completly removed from the room

func (*Room) OnRoomClosed

func (r *Room) OnRoomClosed(callback func(id string))

Use this to get notified when a room is closed

func (*Room) Options

func (r *Room) Options() RoomOptions

func (*Room) SFU

func (r *Room) SFU() *SFU

func (*Room) Stats

func (r *Room) Stats() RoomStats

Get the room real time stats. This will return the current room stats. The client stats and it's tracks will be removed from the stats if the client or track is removed. But the aggregated stats will still be there and included in the room stats even if they're removed.

func (*Room) StopClient

func (r *Room) StopClient(id string) error

Stopping client is async, it will just stop the client and return immediately You should use OnClientLeft to get notified when the client is actually stopped

type RoomOptions

type RoomOptions struct {
	// Configures the bitrates configuration that will be used by the room
	// Make sure to use the same bitrate config when publishing video because this is used to manage the usage bandwidth in this room
	Bitrates BitrateConfigs `json:"bitrates,omitempty"`
	// Configures the codecs that will be used by the room
	Codecs *[]string `` /* 145-byte string literal not displayed */
	// Configures the interval in nanoseconds of sending PLIs to clients that will generate keyframe, default is 0 means it will use auto PLI request only when needed.
	// More often means more bandwidth usage but more stability on video quality when packet loss, but client libs supposed to request PLI automatically when needed.
	PLIInterval *time.Duration `json:"pli_interval_ns,omitempty" example:"0"`
	// Configure the mapping of spatsial and temporal layers to quality level
	// Use this to use scalable video coding (SVC) to control the bitrate level of the video
	QualityLevels []QualityLevel `json:"quality_levels,omitempty"`
	// Configure the timeout in nanonseconds when the room is empty it will close after the timeout exceeded. Default is 5 minutes
	EmptyRoomTimeout *time.Duration `json:"empty_room_timeout_ns,ompitempty" example:"300000000000" default:"300000000000"`
}

func DefaultRoomOptions

func DefaultRoomOptions() RoomOptions

type RoomStats

type RoomStats struct {
	ActiveSessions  int                         `json:"active_sessions"`
	ClientsCount    int                         `json:"clients_count"`
	BitrateSent     uint64                      `json:"bitrate_sent"`
	BitrateReceived uint64                      `json:"bitrate_received"`
	BytesIngress    uint64                      `json:"bytes_ingress"`
	BytesEgress     uint64                      `json:"bytes_egress"`
	ReceivedTracks  StatTracks                  `json:"received_tracks"`
	SentTracks      StatTracks                  `json:"sent_tracks"`
	Timestamp       time.Time                   `json:"timestamp"`
	ClientStats     map[string]ClientTrackStats `json:"client_stats"`
}

type SFU

type SFU struct {
	// contains filtered or unexported fields
}

func New

func New(ctx context.Context, opts sfuOptions) *SFU

@Param muxPort: port for udp mux

func (*SFU) AddRelayTrack

func (s *SFU) AddRelayTrack(ctx context.Context, id, streamid, rid string, client *Client, kind webrtc.RTPCodecType, ssrc webrtc.SSRC, mimeType string, rtpChan chan *rtp.Packet) error

func (*SFU) AvailableTracks

func (s *SFU) AvailableTracks() []ITrack

func (*SFU) CreateDataChannel

func (s *SFU) CreateDataChannel(label string, opts DataChannelOptions) error

func (*SFU) GetClient

func (s *SFU) GetClient(id string) (*Client, error)

func (*SFU) GetClients

func (s *SFU) GetClients() map[string]*Client

func (*SFU) NewClient

func (s *SFU) NewClient(id, name string, opts ClientOptions) *Client

func (*SFU) OnClientAdded

func (s *SFU) OnClientAdded(callback func(*Client))

func (*SFU) OnClientRemoved

func (s *SFU) OnClientRemoved(callback func(*Client))

func (*SFU) OnStopped

func (s *SFU) OnStopped(callback func())

func (*SFU) OnTracksAvailable

func (s *SFU) OnTracksAvailable(callback func(tracks []ITrack))

func (*SFU) PLIInterval

func (s *SFU) PLIInterval() time.Duration

func (*SFU) Stop

func (s *SFU) Stop()

func (*SFU) TotalActiveSessions

func (s *SFU) TotalActiveSessions() int

type SFUClients

type SFUClients struct {
	// contains filtered or unexported fields
}

func (*SFUClients) Add

func (s *SFUClients) Add(client *Client) error

func (*SFUClients) GetClient

func (s *SFUClients) GetClient(id string) (*Client, error)

func (*SFUClients) GetClients

func (s *SFUClients) GetClients() map[string]*Client

func (*SFUClients) Length

func (s *SFUClients) Length() int

func (*SFUClients) Remove

func (s *SFUClients) Remove(client *Client) error

type SFUDataChannel

type SFUDataChannel struct {
	// contains filtered or unexported fields
}

func NewSFUDataChannel

func NewSFUDataChannel(label string, opts DataChannelOptions) *SFUDataChannel

func (*SFUDataChannel) ClientIDs

func (s *SFUDataChannel) ClientIDs() []string

func (*SFUDataChannel) IsOrdered

func (s *SFUDataChannel) IsOrdered() bool

type SFUDataChannelList

type SFUDataChannelList struct {
	// contains filtered or unexported fields
}

func NewSFUDataChannelList

func NewSFUDataChannelList() *SFUDataChannelList

func (*SFUDataChannelList) Add

func (*SFUDataChannelList) Get

func (s *SFUDataChannelList) Get(label string) *SFUDataChannel

func (*SFUDataChannelList) Remove

func (s *SFUDataChannelList) Remove(dc *SFUDataChannel)

type SimulcastTrack

type SimulcastTrack struct {
	// contains filtered or unexported fields
}

func (*SimulcastTrack) AddRemoteTrack

func (t *SimulcastTrack) AddRemoteTrack(track IRemoteTrack, minWait, maxWait time.Duration, stats stats.Getter, onStatsUpdated func(*stats.Stats), onPLI func()) *remoteTrack

func (*SimulcastTrack) ClientID

func (t *SimulcastTrack) ClientID() string

func (*SimulcastTrack) Context

func (t *SimulcastTrack) Context() context.Context

func (*SimulcastTrack) ID

func (t *SimulcastTrack) ID() string

TODO: this is contain multiple tracks, there is a possibility remote track high is not available yet

func (*SimulcastTrack) IsProcessed

func (t *SimulcastTrack) IsProcessed() bool

func (*SimulcastTrack) IsRelay

func (t *SimulcastTrack) IsRelay() bool

func (*SimulcastTrack) IsScaleable

func (t *SimulcastTrack) IsScaleable() bool

func (*SimulcastTrack) IsScreen

func (t *SimulcastTrack) IsScreen() bool

func (*SimulcastTrack) IsSimulcast

func (t *SimulcastTrack) IsSimulcast() bool

func (*SimulcastTrack) IsTrackComplete

func (t *SimulcastTrack) IsTrackComplete() bool

func (*SimulcastTrack) Kind

func (t *SimulcastTrack) Kind() webrtc.RTPCodecType

func (*SimulcastTrack) MimeType

func (t *SimulcastTrack) MimeType() string

func (*SimulcastTrack) OnEnded

func (t *SimulcastTrack) OnEnded(f func())

func (*SimulcastTrack) OnRead

func (t *SimulcastTrack) OnRead(callback func(interceptor.Attributes, *rtp.Packet, QualityLevel))

func (*SimulcastTrack) OnTrackComplete

func (t *SimulcastTrack) OnTrackComplete(f func())

func (*SimulcastTrack) PayloadType

func (t *SimulcastTrack) PayloadType() webrtc.PayloadType

func (*SimulcastTrack) RIDHigh

func (t *SimulcastTrack) RIDHigh() string

func (*SimulcastTrack) RIDLow

func (t *SimulcastTrack) RIDLow() string

func (*SimulcastTrack) RIDMid

func (t *SimulcastTrack) RIDMid() string

func (*SimulcastTrack) Relay

func (t *SimulcastTrack) Relay(f func(webrtc.SSRC, interceptor.Attributes, *rtp.Packet))

func (*SimulcastTrack) SSRCHigh

func (t *SimulcastTrack) SSRCHigh() webrtc.SSRC

func (*SimulcastTrack) SSRCLow

func (t *SimulcastTrack) SSRCLow() webrtc.SSRC

func (*SimulcastTrack) SSRCMid

func (t *SimulcastTrack) SSRCMid() webrtc.SSRC

func (*SimulcastTrack) SetAsProcessed

func (t *SimulcastTrack) SetAsProcessed()

func (*SimulcastTrack) SetSourceType

func (t *SimulcastTrack) SetSourceType(sourceType TrackType)

func (*SimulcastTrack) SourceType

func (t *SimulcastTrack) SourceType() TrackType

func (*SimulcastTrack) StreamID

func (t *SimulcastTrack) StreamID() string

func (*SimulcastTrack) TotalTracks

func (t *SimulcastTrack) TotalTracks() int

type StatTracks

type StatTracks struct {
	Audio int `json:"audio"`
	Video int `json:"video"`
}

type SubscribeTrackRequest

type SubscribeTrackRequest struct {
	ClientID string `json:"client_id"`
	TrackID  string `json:"track_id"`
}

type Track

type Track struct {
	// contains filtered or unexported fields
}

func (*Track) ClientID

func (t *Track) ClientID() string

func (*Track) Context

func (t *Track) Context() context.Context

func (*Track) ID

func (t *Track) ID() string

func (*Track) IsProcessed

func (t *Track) IsProcessed() bool

func (*Track) IsRelay

func (t *Track) IsRelay() bool

func (*Track) IsScaleable

func (t *Track) IsScaleable() bool

func (*Track) IsScreen

func (t *Track) IsScreen() bool

func (*Track) IsSimulcast

func (t *Track) IsSimulcast() bool

func (*Track) Kind

func (t *Track) Kind() webrtc.RTPCodecType

func (*Track) MimeType

func (t *Track) MimeType() string

func (*Track) OnEnded

func (t *Track) OnEnded(f func())

func (*Track) OnRead

func (t *Track) OnRead(callback func(interceptor.Attributes, *rtp.Packet, QualityLevel))

func (*Track) PayloadType

func (t *Track) PayloadType() webrtc.PayloadType

func (*Track) Relay

func (t *Track) Relay(f func(webrtc.SSRC, interceptor.Attributes, *rtp.Packet))

func (*Track) RemoteTrack

func (t *Track) RemoteTrack() *remoteTrack

func (*Track) SSRC

func (t *Track) SSRC() webrtc.SSRC

func (*Track) SSRCHigh

func (t *Track) SSRCHigh() webrtc.SSRC

func (*Track) SSRCLow

func (t *Track) SSRCLow() webrtc.SSRC

func (*Track) SSRCMid

func (t *Track) SSRCMid() webrtc.SSRC

func (*Track) SetAsProcessed

func (t *Track) SetAsProcessed()

func (*Track) SetSourceType

func (t *Track) SetSourceType(sourceType TrackType)

func (*Track) SourceType

func (t *Track) SourceType() TrackType

func (*Track) StreamID

func (t *Track) StreamID() string

func (*Track) TotalTracks

func (t *Track) TotalTracks() int

type TrackReceivedStats

type TrackReceivedStats struct {
	ID              string              `json:"id"`
	StreamID        string              `json:"stream_id"`
	RID             string              `json:"rid"`
	Kind            webrtc.RTPCodecType `json:"kind"`
	Codec           string              `json:"codec"`
	CurrentBitrate  uint32              `json:"current_bitrate"`
	PacketsLost     int64               `json:"packets_lost"`
	PacketsReceived uint64              `json:"packets_received"`
	BytesReceived   int64               `json:"bytes_received"`
}

type TrackSentStats

type TrackSentStats struct {
	ID             string              `json:"id"`
	StreamID       string              `json:"stream_id"`
	Kind           webrtc.RTPCodecType `json:"kind"`
	Codec          string              `json:"codec"`
	PacketsLost    int64               `json:"packets_lost"`
	PacketSent     uint64              `json:"packets_sent"`
	FractionLost   float64             `json:"fraction_lost"`
	BytesSent      uint64              `json:"bytes_sent"`
	CurrentBitrate uint32              `json:"current_bitrate"`
	Source         string              `json:"source"`
	Quality        QualityLevel        `json:"quality"`
	MaxQuality     QualityLevel        `json:"max_quality"`
}

type TrackStats

type TrackStats struct {
	// contains filtered or unexported fields
}

type TrackType

type TrackType string

func (TrackType) String

func (t TrackType) String() string

type UDPMux

type UDPMux struct {
	Port int
	// contains filtered or unexported fields
}

func NewUDPMux

func NewUDPMux(ctx context.Context, port int) *UDPMux

func (*UDPMux) Close

func (u *UDPMux) Close() error

func (*UDPMux) Mux

func (u *UDPMux) Mux() *ice.MultiUDPMuxDefault

Directories

Path Synopsis
examples
pkg
pacer
modified version of pion interceptor leaky_bucket_pacer.go https://github.com/pion/interceptor/blob/master/pkg/gcc/leaky_bucket_pacer.go
modified version of pion interceptor leaky_bucket_pacer.go https://github.com/pion/interceptor/blob/master/pkg/gcc/leaky_bucket_pacer.go
packetmap
Credit to Galene https://github.com/jech/galene/blob/master/packetmap/packetmap.go Package packetmap implements remapping of sequence numbers and picture ids.
Credit to Galene https://github.com/jech/galene/blob/master/packetmap/packetmap.go Package packetmap implements remapping of sequence numbers and picture ids.
rtppool
this code is from pion nack interceptor https://github.com/pion/interceptor/blob/master/pkg/nack/retainable_packet.go
this code is from pion nack interceptor https://github.com/pion/interceptor/blob/master/pkg/nack/retainable_packet.go

Jump to

Keyboard shortcuts

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