Skip to content

Commit

Permalink
Supports more scalability mode (#1104)
Browse files Browse the repository at this point in the history
* Supports more scalability mode

* changeset
  • Loading branch information
cnderrauber authored Apr 10, 2024
1 parent 5dee4c9 commit b1e41d5
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/unlucky-dolls-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"livekit-client": patch
---

Support more scalability mode
8 changes: 8 additions & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ <h2>Livekit Sample App</h2>
<div>
<select id="preferred-codec" class="custom-select" style="width: auto"></select>
</div>
<div>
<select
id="scalability-mode"
class="custom-select"
style="width: auto"
disabled="true"
></select>
</div>
</div>

<!-- actions -->
Expand Down
52 changes: 52 additions & 0 deletions example/sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ import {
supportsAV1,
supportsVP9,
} from '../src/index';
import { ScalabilityMode } from '../src/room/track/options';
import type { SimulationScenario } from '../src/room/types';
import { isSVCCodec } from '../src/room/utils';

const $ = <T extends HTMLElement>(id: string) => document.getElementById(id) as T;

Expand Down Expand Up @@ -74,6 +76,7 @@ const appActions = {
const adaptiveStream = (<HTMLInputElement>$('adaptive-stream')).checked;
const shouldPublish = (<HTMLInputElement>$('publish-option')).checked;
const preferredCodec = (<HTMLSelectElement>$('preferred-codec')).value as VideoCodec;
const scalabilityMode = (<HTMLSelectElement>$('scalability-mode')).value;
const cryptoKey = (<HTMLSelectElement>$('crypto-key')).value;
const autoSubscribe = (<HTMLInputElement>$('auto-subscribe')).checked;
const e2eeEnabled = (<HTMLInputElement>$('e2ee')).checked;
Expand Down Expand Up @@ -109,6 +112,9 @@ const appActions = {
roomOpts.publishDefaults?.videoCodec === 'vp9'
) {
roomOpts.publishDefaults.backupCodec = true;
if (scalabilityMode !== '') {
roomOpts.publishDefaults.scalabilityMode = scalabilityMode as ScalabilityMode;
}
}

const connectOpts: RoomConnectOptions = {
Expand Down Expand Up @@ -914,5 +920,51 @@ function populateSupportedCodecs() {
}
}

function populateScalabilityModes() {
const modeSelect = $('scalability-mode');
const modes: string[] = [
'L1T2',
'L1T3',
'L2T1',
'L2T1h',
'L2T1_KEY',
'L2T2',
'L2T2h',
'L2T2_KEY',
'L2T3',
'L2T3h',
'L2T3_KEY',
'L3T1',
'L3T1h',
'L3T1_KEY',
'L3T2',
'L3T2h',
'L3T2_KEY',
'L3T3',
'L3T3h',
'L3T3_KEY',
];
let n = document.createElement('option');
n.value = '';
n.text = 'ScalabilityMode';
modeSelect.appendChild(n);
for (const mode of modes) {
n = document.createElement('option');
n.value = mode;
n.text = mode;
modeSelect.appendChild(n);
}

const codecSelect = <HTMLSelectElement>$('preferred-codec');
codecSelect.onchange = () => {
if (isSVCCodec(codecSelect.value)) {
modeSelect.removeAttribute('disabled');
} else {
modeSelect.setAttribute('disabled', 'true');
}
};
}

acquireDeviceList();
populateSupportedCodecs();
populateScalabilityModes();
3 changes: 2 additions & 1 deletion src/room/participant/publishUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,12 @@ export function computeVideoEncodings(
isSafari() ||
(browser?.name === 'Chrome' && compareVersions(browser?.version, '113') < 0)
) {
const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
for (let i = 0; i < sm.spatial; i += 1) {
// in legacy SVC, scaleResolutionDownBy cannot be set
encodings.push({
rid: videoRids[2 - i],
maxBitrate: videoEncoding.maxBitrate / 3 ** i,
maxBitrate: videoEncoding.maxBitrate / bitratesRatio ** i,
maxFramerate: original.encoding.maxFramerate,
});
}
Expand Down
10 changes: 7 additions & 3 deletions src/room/track/LocalVideoTrack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,13 +572,17 @@ export function videoLayersFromEncodings(
const encodingSM = encodings[0].scalabilityMode as string;
const sm = new ScalabilityMode(encodingSM);
const layers = [];
const resRatio = sm.suffix == 'h' ? 1.5 : 2;
const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
for (let i = 0; i < sm.spatial; i += 1) {
layers.push(
new VideoLayer({
quality: VideoQuality.HIGH - i,
width: Math.ceil(width / 2 ** i),
height: Math.ceil(height / 2 ** i),
bitrate: encodings[0].maxBitrate ? Math.ceil(encodings[0].maxBitrate / 3 ** i) : 0,
width: Math.ceil(width / resRatio ** i),
height: Math.ceil(height / resRatio ** i),
bitrate: encodings[0].maxBitrate
? Math.ceil(encodings[0].maxBitrate / bitratesRatio ** i)
: 0,
ssrc: 0,
}),
);
Expand Down
22 changes: 21 additions & 1 deletion src/room/track/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,27 @@ export function isBackupCodec(codec: string): codec is BackupVideoCodec {
/**
* scalability modes for svc.
*/
export type ScalabilityMode = 'L1T3' | 'L2T3' | 'L2T3_KEY' | 'L3T3' | 'L3T3_KEY';
export type ScalabilityMode =
| 'L1T2'
| 'L1T3'
| 'L2T1'
| 'L2T1h'
| 'L2T1_KEY'
| 'L2T2'
| 'L2T2h'
| 'L2T2_KEY'
| 'L2T3'
| 'L2T3h'
| 'L2T3_KEY'
| 'L3T1'
| 'L3T1h'
| 'L3T1_KEY'
| 'L3T2'
| 'L3T2h'
| 'L3T2_KEY'
| 'L3T3'
| 'L3T3h'
| 'L3T3_KEY';

export namespace AudioPresets {
export const telephone: AudioPreset = {
Expand Down

0 comments on commit b1e41d5

Please sign in to comment.