Capture bandwidth switch (#14)

* Handle bitrate change by finding the stream with closest bitrate as peer

* Convert video id into bitrate when creating peer or changing bitrate

* Try to fix prometheus panic

* Revert metrics label name change

* minor fixes.

* bitrate selector.

* skip if moving to the same stream.

* no closure for getting target bitrate.

* fix: high res switch to lo video, stream bitrate out of range

* revert dev config change.

* white space.

Co-authored-by: Aleksandar Sukovic <aleksandar.sukovic@gmail.com>
This commit is contained in:
Miroslav Šedivý
2022-10-25 20:25:00 +02:00
committed by GitHub
parent e0bee67e85
commit 6067367acd
10 changed files with 186 additions and 52 deletions

View File

@ -22,7 +22,7 @@ type Sample media.Sample
type Receiver interface {
SetStream(stream StreamSinkManager) error
RemoveStream()
OnVideoIdChange(f func(string) error)
OnBitrateChange(f func(int) error)
}
type BucketsManager interface {
@ -46,6 +46,7 @@ type ScreencastManager interface {
}
type StreamSinkManager interface {
ID() string
Codec() codec.RTPCodec
AddListener(listener *func(sample Sample)) error
@ -70,6 +71,8 @@ type CaptureManager interface {
Start()
Shutdown() error
GetBitrateFromVideoID(videoID string) (int, error)
Broadcast() BroadcastManager
Screencast() ScreencastManager
Audio() StreamSinkManager
@ -83,6 +86,7 @@ type VideoConfig struct {
Width string `mapstructure:"width"` // expression
Height string `mapstructure:"height"` // expression
Fps string `mapstructure:"fps"` // expression
Bitrate int `mapstructure:"bitrate"` // pipeline bitrate
GstPrefix string `mapstructure:"gst_prefix"` // pipeline prefix, starts with !
GstEncoder string `mapstructure:"gst_encoder"` // gst encoder name
GstParams map[string]string `mapstructure:"gst_params"` // map of expressions
@ -173,3 +177,41 @@ func (config *VideoConfig) GetPipeline(screen ScreenSize) (string, error) {
config.GstSuffix,
}[:], " "), nil
}
func (config *VideoConfig) GetBitrateFn(getScreen func() *ScreenSize) func() (int, error) {
return func() (int, error) {
if config.Bitrate > 0 {
return config.Bitrate, nil
}
screen := getScreen()
if screen == nil {
return 0, fmt.Errorf("screen is nil")
}
values := map[string]any{
"width": screen.Width,
"height": screen.Height,
"fps": screen.Rate,
}
language := []gval.Language{
gval.Function("round", func(args ...any) (any, error) {
return (int)(math.Round(args[0].(float64))), nil
}),
}
// TODO: This is only for vp8.
expr, ok := config.GstParams["target-bitrate"]
if !ok {
return 0, fmt.Errorf("target-bitrate not found")
}
targetBitrate, err := gval.Evaluate(expr, values, language...)
if err != nil {
return 0, err
}
return targetBitrate.(int), nil
}
}

View File

@ -48,7 +48,7 @@ type SystemDisconnect struct {
type SignalProvide struct {
SDP string `json:"sdp"`
ICEServers []types.ICEServer `json:"iceservers"`
Video string `json:"video"`
Video string `json:"video"` // TODO: Refactor.
}
type SignalCandidate struct {
@ -60,7 +60,8 @@ type SignalDescription struct {
}
type SignalVideo struct {
Video string `json:"video"`
Video string `json:"video"` // TODO: Refactor.
Bitrate int `json:"bitrate"`
}
/////////////////////////////

View File

@ -7,7 +7,6 @@ import (
)
var (
ErrWebRTCVideoNotFound = errors.New("webrtc video not found")
ErrWebRTCDataChannelNotFound = errors.New("webrtc data channel not found")
ErrWebRTCConnectionNotFound = errors.New("webrtc connection not found")
)
@ -25,7 +24,8 @@ type WebRTCPeer interface {
SetAnswer(sdp string) error
SetCandidate(candidate webrtc.ICECandidateInit) error
SetVideoID(videoID string) error
SetVideoBitrate(bitrate int) error
GetVideoId() string
SetPaused(isPaused bool) error
SendCursorPosition(x, y int) error
@ -40,6 +40,6 @@ type WebRTCManager interface {
ICEServers() []ICEServer
CreatePeer(session Session, videoID string) (*webrtc.SessionDescription, error)
CreatePeer(session Session, bitrate int) (*webrtc.SessionDescription, error)
SetCursorPosition(x, y int)
}