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
1 change: 1 addition & 0 deletions .changes/align-screenshare-simulcast-defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
patch type="fixed" "Align screen share simulcast defaults"
4 changes: 2 additions & 2 deletions lib/src/types/video_parameters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ extension VideoParametersPresets on VideoParameters {
static const screenShareH720FPS5 = VideoParameters(
dimensions: VideoDimensionsPresets.h720_169,
encoding: VideoEncoding(
maxBitrate: 400 * 1000,
maxBitrate: 800 * 1000,
maxFramerate: 5,
),
);
Expand All @@ -298,7 +298,7 @@ extension VideoParametersPresets on VideoParameters {
static const screenShareH1080FPS30 = VideoParameters(
dimensions: VideoDimensionsPresets.h1080_169,
encoding: VideoEncoding(
maxBitrate: 4000 * 1000,
maxBitrate: 5000 * 1000,
maxFramerate: 30,
),
);
Expand Down
19 changes: 10 additions & 9 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -229,23 +229,24 @@ class Utils {
static List<VideoParameters> _computeDefaultScreenShareSimulcastParams({
required VideoParameters original,
}) {
final layers = [rtc.RTCRtpEncoding(scaleResolutionDownBy: 2, maxFramerate: 3)];
return layers.map((e) {
final scale = e.scaleResolutionDownBy ?? 1;
final fps = e.maxFramerate ?? 3;
final originalEncoding = original.encoding!;
const scale = 2.0;

return VideoParameters(
return [
VideoParameters(
dimensions:
VideoDimensions((original.dimensions.width / scale).floor(), (original.dimensions.height / scale).floor()),
encoding: VideoEncoding(
maxBitrate: math.max(
150 * 1000,
(original.encoding!.maxBitrate / (math.pow(scale, 2) * (original.encoding!.maxFramerate / fps))).floor(),
(originalEncoding.maxBitrate / math.pow(scale, 2)).floor(),
),
maxFramerate: fps,
maxFramerate: originalEncoding.maxFramerate,
bitratePriority: originalEncoding.bitratePriority,
networkPriority: originalEncoding.networkPriority,
),
);
}).toList();
),
];
}

static List<VideoParameters> _computeDefaultSimulcastParams({
Expand Down
34 changes: 34 additions & 0 deletions test/utils_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
// limitations under the License.

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;

import 'package:livekit_client/livekit_client.dart' as lk;
import 'package:livekit_client/src/utils.dart';

void main() {
Expand Down Expand Up @@ -54,4 +56,36 @@ void main() {
),
);
});

group('screen share simulcast encodings', () {
test('screen share preset bitrates match common SDK presets', () {
expect(lk.VideoParametersPresets.screenShareH720FPS5.encoding?.maxBitrate, 800000);
expect(lk.VideoParametersPresets.screenShareH1080FPS30.encoding?.maxBitrate, 5000000);
});

test('default lower layer follows top layer fps and priorities', () {
final encodings = Utils.computeVideoEncodings(
isScreenShare: true,
dimensions: const lk.VideoDimensions(1920, 1080),
options: const lk.VideoPublishOptions(
screenShareEncoding: lk.VideoEncoding(
maxBitrate: 2500000,
maxFramerate: 15,
bitratePriority: lk.Priority.high,
networkPriority: lk.Priority.high,
),
),
);

expect(encodings, hasLength(2));

final lowLayer = encodings![0];
expect(lowLayer.rid, 'q');
expect(lowLayer.scaleResolutionDownBy, 2);
expect(lowLayer.maxFramerate, 15);
expect(lowLayer.maxBitrate, 625000);
expect(lowLayer.priority, rtc.RTCPriorityType.high);
expect(lowLayer.networkPriority, rtc.RTCPriorityType.high);
});
});
}
Loading