Clients can provide the maximum publishing bandwidth in offer requests.
This will still be capped to any backend / proxy / Janus limits.
This commit is contained in:
parent
414f78dd87
commit
ffd8a30f61
|
@ -411,6 +411,7 @@ type MessageClientMessageData struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Sid string `json:"sid"`
|
Sid string `json:"sid"`
|
||||||
RoomType string `json:"roomType"`
|
RoomType string `json:"roomType"`
|
||||||
|
Bitrate int `json:"bitrate,omitempty"`
|
||||||
Payload map[string]interface{} `json:"payload"`
|
Payload map[string]interface{} `json:"payload"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -820,12 +820,18 @@ func (s *ClientSession) GetOrCreatePublisher(ctx context.Context, mcu Mcu, strea
|
||||||
client := s.getClientUnlocked()
|
client := s.getClientUnlocked()
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
var bitrate int
|
bitrate := data.Bitrate
|
||||||
if backend := s.Backend(); backend != nil {
|
if backend := s.Backend(); backend != nil {
|
||||||
|
var maxBitrate int
|
||||||
if streamType == streamTypeScreen {
|
if streamType == streamTypeScreen {
|
||||||
bitrate = backend.maxScreenBitrate
|
maxBitrate = backend.maxScreenBitrate
|
||||||
} else {
|
} else {
|
||||||
bitrate = backend.maxStreamBitrate
|
maxBitrate = backend.maxStreamBitrate
|
||||||
|
}
|
||||||
|
if bitrate <= 0 {
|
||||||
|
bitrate = maxBitrate
|
||||||
|
} else if maxBitrate > 0 && bitrate > maxBitrate {
|
||||||
|
bitrate = maxBitrate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
package signaling
|
package signaling
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -122,3 +124,179 @@ func Test_permissionsEqual(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBandwidth_Client(t *testing.T) {
|
||||||
|
hub, _, _, server, shutdown := CreateHubForTest(t)
|
||||||
|
defer shutdown()
|
||||||
|
|
||||||
|
mcu, err := NewTestMCU()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if err := mcu.Start(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer mcu.Stop()
|
||||||
|
|
||||||
|
hub.SetMcu(mcu)
|
||||||
|
|
||||||
|
client := NewTestClient(t, server, hub)
|
||||||
|
defer client.CloseWithBye()
|
||||||
|
|
||||||
|
if err := client.SendHello(testDefaultUserId); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
hello, err := client.RunUntilHello(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join room by id.
|
||||||
|
roomId := "test-room"
|
||||||
|
if room, err := client.JoinRoom(ctx, roomId); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if room.Room.RoomId != roomId {
|
||||||
|
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will receive a "joined" event.
|
||||||
|
if err := client.RunUntilJoined(ctx, hello.Hello); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client may not send an offer with audio and video.
|
||||||
|
bitrate := 10000
|
||||||
|
if err := client.SendMessage(MessageClientMessageRecipient{
|
||||||
|
Type: "session",
|
||||||
|
SessionId: hello.Hello.SessionId,
|
||||||
|
}, MessageClientMessageData{
|
||||||
|
Type: "offer",
|
||||||
|
Sid: "54321",
|
||||||
|
RoomType: "video",
|
||||||
|
Bitrate: bitrate,
|
||||||
|
Payload: map[string]interface{}{
|
||||||
|
"sdp": MockSdpOfferAudioAndVideo,
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.RunUntilAnswer(ctx, MockSdpAnswerAudioAndVideo); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := mcu.GetPublisher(hello.Hello.SessionId)
|
||||||
|
if pub == nil {
|
||||||
|
t.Fatal("Could not find publisher")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pub.bitrate != bitrate {
|
||||||
|
t.Errorf("Expected bitrate %d, got %d", bitrate, pub.bitrate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBandwidth_Backend(t *testing.T) {
|
||||||
|
hub, _, _, server, shutdown := CreateHubWithMultipleBackendsForTest(t)
|
||||||
|
defer shutdown()
|
||||||
|
|
||||||
|
u, err := url.Parse(server.URL + "/one")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
backend := hub.backend.GetBackend(u)
|
||||||
|
if backend == nil {
|
||||||
|
t.Fatal("Could not get backend")
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.maxScreenBitrate = 1000
|
||||||
|
backend.maxStreamBitrate = 2000
|
||||||
|
|
||||||
|
mcu, err := NewTestMCU()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if err := mcu.Start(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer mcu.Stop()
|
||||||
|
|
||||||
|
hub.SetMcu(mcu)
|
||||||
|
|
||||||
|
streamTypes := []string{
|
||||||
|
streamTypeVideo,
|
||||||
|
streamTypeScreen,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
for _, streamType := range streamTypes {
|
||||||
|
t.Run(streamType, func(t *testing.T) {
|
||||||
|
client := NewTestClient(t, server, hub)
|
||||||
|
defer client.CloseWithBye()
|
||||||
|
|
||||||
|
params := TestBackendClientAuthParams{
|
||||||
|
UserId: testDefaultUserId,
|
||||||
|
}
|
||||||
|
if err := client.SendHelloParams(server.URL+"/one", "client", params); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hello, err := client.RunUntilHello(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join room by id.
|
||||||
|
roomId := "test-room"
|
||||||
|
if room, err := client.JoinRoom(ctx, roomId); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if room.Room.RoomId != roomId {
|
||||||
|
t.Fatalf("Expected room %s, got %s", roomId, room.Room.RoomId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will receive a "joined" event.
|
||||||
|
if err := client.RunUntilJoined(ctx, hello.Hello); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client may not send an offer with audio and video.
|
||||||
|
bitrate := 10000
|
||||||
|
if err := client.SendMessage(MessageClientMessageRecipient{
|
||||||
|
Type: "session",
|
||||||
|
SessionId: hello.Hello.SessionId,
|
||||||
|
}, MessageClientMessageData{
|
||||||
|
Type: "offer",
|
||||||
|
Sid: "54321",
|
||||||
|
RoomType: streamType,
|
||||||
|
Bitrate: bitrate,
|
||||||
|
Payload: map[string]interface{}{
|
||||||
|
"sdp": MockSdpOfferAudioAndVideo,
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := client.RunUntilAnswer(ctx, MockSdpAnswerAudioAndVideo); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := mcu.GetPublisher(hello.Hello.SessionId)
|
||||||
|
if pub == nil {
|
||||||
|
t.Fatal("Could not find publisher")
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectBitrate int
|
||||||
|
if streamType == streamTypeVideo {
|
||||||
|
expectBitrate = backend.maxStreamBitrate
|
||||||
|
} else {
|
||||||
|
expectBitrate = backend.maxScreenBitrate
|
||||||
|
}
|
||||||
|
if pub.bitrate != expectBitrate {
|
||||||
|
t.Errorf("Expected bitrate %d, got %d", expectBitrate, pub.bitrate)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
mcu_test.go
18
mcu_test.go
|
@ -31,6 +31,11 @@ import (
|
||||||
"github.com/dlintw/goconf"
|
"github.com/dlintw/goconf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TestMaxBitrateScreen = 12345678
|
||||||
|
TestMaxBitrateVideo = 23456789
|
||||||
|
)
|
||||||
|
|
||||||
type TestMCU struct {
|
type TestMCU struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
publishers map[string]*TestMCUPublisher
|
publishers map[string]*TestMCUPublisher
|
||||||
|
@ -63,6 +68,17 @@ func (m *TestMCU) GetStats() interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TestMCU) NewPublisher(ctx context.Context, listener McuListener, id string, streamType string, bitrate int, mediaTypes MediaType, initiator McuInitiator) (McuPublisher, error) {
|
func (m *TestMCU) NewPublisher(ctx context.Context, listener McuListener, id string, streamType string, bitrate int, mediaTypes MediaType, initiator McuInitiator) (McuPublisher, error) {
|
||||||
|
var maxBitrate int
|
||||||
|
if streamType == streamTypeScreen {
|
||||||
|
maxBitrate = TestMaxBitrateScreen
|
||||||
|
} else {
|
||||||
|
maxBitrate = TestMaxBitrateVideo
|
||||||
|
}
|
||||||
|
if bitrate <= 0 {
|
||||||
|
bitrate = maxBitrate
|
||||||
|
} else if bitrate > maxBitrate {
|
||||||
|
bitrate = maxBitrate
|
||||||
|
}
|
||||||
pub := &TestMCUPublisher{
|
pub := &TestMCUPublisher{
|
||||||
TestMCUClient: TestMCUClient{
|
TestMCUClient: TestMCUClient{
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -70,6 +86,7 @@ func (m *TestMCU) NewPublisher(ctx context.Context, listener McuListener, id str
|
||||||
},
|
},
|
||||||
|
|
||||||
mediaTypes: mediaTypes,
|
mediaTypes: mediaTypes,
|
||||||
|
bitrate: bitrate,
|
||||||
}
|
}
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
|
@ -129,6 +146,7 @@ type TestMCUPublisher struct {
|
||||||
TestMCUClient
|
TestMCUClient
|
||||||
|
|
||||||
mediaTypes MediaType
|
mediaTypes MediaType
|
||||||
|
bitrate int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *TestMCUPublisher) HasMedia(mt MediaType) bool {
|
func (p *TestMCUPublisher) HasMedia(mt MediaType) bool {
|
||||||
|
|
Loading…
Reference in New Issue