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
}
}