WebRTC congestion control (#26)

* Add congestion control

* Improve stream matching, add manual stream selection, add metrics

* Use a ticker for bitrate estimation and make bandwidth drops switch to lower streams more aggressively

* Missing signal response, fix video auto bug

* Remove redundant mutex

* Bitrate history queue

* Get bitrate fn support h264 & float64

---------

Co-authored-by: Aleksandar Sukovic <aleksandar.sukovic@gmail.com>
This commit is contained in:
Miroslav Šedivý
2023-02-06 19:45:51 +01:00
committed by GitHub
parent e80ae8019e
commit 2364facd60
15 changed files with 738 additions and 222 deletions

View File

@ -8,9 +8,8 @@ import (
"strings"
"github.com/PaesslerAG/gval"
"github.com/pion/webrtc/v3/pkg/media"
"github.com/demodesk/neko/pkg/types/codec"
"github.com/pion/webrtc/v3/pkg/media"
)
var (
@ -20,16 +19,23 @@ var (
type Sample media.Sample
type Receiver interface {
SetStream(stream StreamSinkManager) error
SetStream(stream StreamSinkManager) (changed bool, err error)
RemoveStream()
OnBitrateChange(f func(int) error)
OnBitrateChange(f func(bitrate int) (changed bool, err error))
OnVideoChange(f func(videoID string) (changed bool, err error))
VideoAuto() bool
SetVideoAuto(videoAuto bool)
}
type BucketsManager interface {
IDs() []string
Codec() codec.RTPCodec
SetReceiver(receiver Receiver) error
SetReceiver(receiver Receiver)
RemoveReceiver(receiver Receiver) error
DestroyAll()
RecreateAll() error
Shutdown()
}
type BroadcastManager interface {
@ -48,6 +54,7 @@ type ScreencastManager interface {
type StreamSinkManager interface {
ID() string
Codec() codec.RTPCodec
Bitrate() int
AddListener(listener *func(sample Sample)) error
RemoveListener(listener *func(sample Sample)) error
@ -55,6 +62,9 @@ type StreamSinkManager interface {
ListenersCount() int
Started() bool
CreatePipeline() error
DestroyPipeline()
}
type StreamSrcManager interface {
@ -201,17 +211,33 @@ func (config *VideoConfig) GetBitrateFn(getScreen func() *ScreenSize) func() (in
}),
}
// TOOD: do not read target-bitrate from pipeline, but only from config.
// TODO: This is only for vp8.
expr, ok := config.GstParams["target-bitrate"]
if !ok {
return 0, fmt.Errorf("target-bitrate not found")
// TODO: This is only for h264.
expr, ok = config.GstParams["bitrate"]
if !ok {
return 0, fmt.Errorf("bitrate not found")
}
}
targetBitrate, err := gval.Evaluate(expr, values, language...)
bitrate, err := gval.Evaluate(expr, values, language...)
if err != nil {
return 0, err
return 0, fmt.Errorf("failed to evaluate bitrate: %w", err)
}
return targetBitrate.(int), nil
var bitrateInt int
switch val := bitrate.(type) {
case int:
bitrateInt = val
case float64:
bitrateInt = (int)(val)
default:
return 0, fmt.Errorf("bitrate is not int or float64")
}
return bitrateInt, nil
}
}

View File

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

View File

@ -25,8 +25,11 @@ type WebRTCPeer interface {
SetCandidate(candidate webrtc.ICECandidateInit) error
SetVideoBitrate(bitrate int) error
GetVideoId() string
SetVideoID(videoID string) error
GetVideoID() string
SetPaused(isPaused bool) error
SetVideoAuto(auto bool)
VideoAuto() bool
SendCursorPosition(x, y int) error
SendCursorImage(cur *CursorImage, img []byte) error
@ -40,6 +43,6 @@ type WebRTCManager interface {
ICEServers() []ICEServer
CreatePeer(session Session, bitrate int) (*webrtc.SessionDescription, error)
CreatePeer(session Session, bitrate int, videoAuto bool) (*webrtc.SessionDescription, error)
SetCursorPosition(x, y int)
}