Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/lk/egress.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ func testEgressTemplate(ctx context.Context, cmd *cli.Command) error {
}

testers = append(testers, lt)
if _, err = lt.PublishSimulcastTrack("demo-video", "high", ""); err != nil {
if _, err = lt.PublishSimulcastTrack("demo-video", "high", "", 0); err != nil {
return err
}
}
Expand Down
11 changes: 11 additions & 0 deletions cmd/lk/perf.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ var (
Name: "simulate-speakers",
Usage: "Fire random speaker events to simulate speaker changes",
},
&cli.IntFlag{
Name: "video-bitrate",
Usage: "`BITRATE` in kbps for video publishing (overrides resolution-based bitrate, e.g., 10000 for 10Mbps)",
Value: 0,
},
&cli.BoolFlag{
Name: "run-all",
Usage: "Runs set list of load test cases",
Expand Down Expand Up @@ -170,6 +175,11 @@ var (
Name: "simulate-speakers",
Usage: "Fire random speaker events to simulate speaker changes",
},
&cli.IntFlag{
Name: "video-bitrate",
Usage: "`BITRATE` in kbps for video publishing (overrides resolution-based bitrate, e.g., 10000 for 10Mbps)",
Value: 0,
},
&cli.BoolFlag{
Name: "run-all",
Usage: "Runs set list of load test cases",
Expand All @@ -194,6 +204,7 @@ func loadTest(ctx context.Context, cmd *cli.Command) error {
params := loadtester.Params{
VideoResolution: cmd.String("video-resolution"),
VideoCodec: cmd.String("video-codec"),
VideoBitrate: uint32(cmd.Int("video-bitrate")),
Duration: cmd.Duration("duration"),
NumPerSecond: cmd.Float("num-per-second"),
Simulcast: !cmd.Bool("no-simulcast"),
Expand Down
9 changes: 6 additions & 3 deletions pkg/loadtester/loadtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ type Params struct {
VideoPublishers int
AudioPublishers int
Subscribers int

VideoResolution string
VideoCodec string
Duration time.Duration
VideoBitrate uint32 // Custom bitrate in kbps, 0 means use resolution-based default

Duration time.Duration
// number of seconds to spin up per second
NumPerSecond float64
Simulcast bool
Expand Down Expand Up @@ -347,9 +350,9 @@ func (t *LoadTest) run(ctx context.Context, params Params) (map[string]*testerSt
var video string
var err error
if params.Simulcast {
video, err = tester.PublishSimulcastTrack("video-simulcast", params.VideoResolution, params.VideoCodec)
video, err = tester.PublishSimulcastTrack("video-simulcast", params.VideoResolution, params.VideoCodec, params.VideoBitrate)
} else {
video, err = tester.PublishVideoTrack("video", params.VideoResolution, params.VideoCodec)
video, err = tester.PublishVideoTrack("video", params.VideoResolution, params.VideoCodec, params.VideoBitrate)
}
if err != nil {
errs.Store(testerParams.name, err)
Expand Down
79 changes: 77 additions & 2 deletions pkg/loadtester/loadtester.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,38 @@ func (t *LoadTester) PublishAudioTrack(name string) (string, error) {
return p.SID(), nil
}

func (t *LoadTester) PublishVideoTrack(name, resolution, codec string) (string, error) {
func (t *LoadTester) PublishVideoTrack(name, resolution, codec string, bitrate uint32) (string, error) {
if !t.IsRunning() {
return "", nil
}

fmt.Println("publishing video track -", t.room.LocalParticipant.Identity())

// Use LoadTestProvider for custom bitrate
if bitrate > 0 {
provider, err := NewLoadTestProvider(bitrate * 1000) // Convert kbps to bps
if err != nil {
return "", err
}
track, err := lksdk.NewLocalTrack(webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeH264,
})
if err != nil {
return "", err
}
if err := track.StartWrite(provider, nil); err != nil {
return "", err
}
p, err := t.room.LocalParticipant.PublishTrack(track, &lksdk.TrackPublicationOptions{
Name: name,
})
if err != nil {
return "", err
}
return p.SID(), nil
}

// Use embedded video files for default behavior
loopers, err := provider2.CreateVideoLoopers(resolution, codec, false)
if err != nil {
return "", err
Expand All @@ -201,10 +227,59 @@ func (t *LoadTester) PublishVideoTrack(name, resolution, codec string) (string,
return p.SID(), nil
}

func (t *LoadTester) PublishSimulcastTrack(name, resolution, codec string) (string, error) {
func (t *LoadTester) PublishSimulcastTrack(name, resolution, codec string, bitrate uint32) (string, error) {
var tracks []*lksdk.LocalTrack

fmt.Println("publishing simulcast video track -", t.room.LocalParticipant.Identity())

if bitrate > 0 {
layers := []struct {
quality livekit.VideoQuality
bitrate uint32
width uint32
height uint32
}{
{livekit.VideoQuality_HIGH, bitrate, 1280, 720},
{livekit.VideoQuality_MEDIUM, bitrate / 2, 640, 360},
{livekit.VideoQuality_LOW, bitrate / 4, 320, 180},
}

for _, layer := range layers {
provider, err := NewLoadTestProvider(layer.bitrate * 1000)
if err != nil {
return "", err
}

videoLayer := &livekit.VideoLayer{
Quality: layer.quality,
Width: layer.width,
Height: layer.height,
Bitrate: layer.bitrate * 1000,
}

track, err := lksdk.NewLocalTrack(webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeH264,
}, lksdk.WithSimulcast("loadtest-video", videoLayer))
if err != nil {
return "", err
}
if err := track.StartWrite(provider, nil); err != nil {
return "", err
}
tracks = append(tracks, track)
}

p, err := t.room.LocalParticipant.PublishSimulcastTrack(tracks, &lksdk.TrackPublicationOptions{
Name: name,
Source: livekit.TrackSource_CAMERA,
})
if err != nil {
return "", err
}
return p.SID(), nil
}

// Use embedded video files for default behavior
loopers, err := provider2.CreateVideoLoopers(resolution, codec, true)
if err != nil {
return "", err
Expand Down
7 changes: 6 additions & 1 deletion pkg/loadtester/loadtestprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package loadtester

import (
"bytes"
"context"
"encoding/binary"
"errors"
"time"
Expand All @@ -42,7 +43,7 @@ func NewLoadTestProvider(bitrate uint32) (*LoadTestProvider, error) {
}, nil
}

func (p *LoadTestProvider) NextSample() (media.Sample, error) {
func (p *LoadTestProvider) NextSample(ctx context.Context) (media.Sample, error) {
// sample format:
// 0xfafafa + 0000... + 8 bytes for ts
buf := bytes.NewBuffer(nil)
Expand All @@ -68,6 +69,10 @@ func (p *LoadTestProvider) OnUnbind() error {
return nil
}

func (p *LoadTestProvider) Close() error {
return nil
}

type LoadTestDepacketizer struct {
}

Expand Down