optimizations for low-powered devices (#438)

* ensure low power devices don't use high quality for krisp

* Update MicrophoneSettings.tsx

* use lower video publish settings

* fix import

* comments

---------

Co-authored-by: David Zhao <dz@livekit.io>
This commit is contained in:
lukasIO 2025-06-15 02:23:36 +02:00 committed by GitHub
parent c4ea8a31ec
commit c99a780f58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 47 additions and 17 deletions

View File

@ -1,7 +1,7 @@
'use client';
import React from 'react';
import { decodePassphrase } from '@/lib/client-utils';
import { decodePassphrase, isLowPowerDevice } from '@/lib/client-utils';
import { DebugMode } from '@/lib/Debug';
import { KeyboardShortcuts } from '@/lib/KeyboardShortcuts';
import { RecordingIndicator } from '@/lib/RecordingIndicator';
@ -23,6 +23,8 @@ import {
DeviceUnsupportedError,
RoomConnectOptions,
RoomEvent,
TrackPublishDefaults,
VideoCaptureOptions,
} from 'livekit-client';
import { useRouter } from 'next/navigation';
import { useSetupE2EE } from '@/lib/useSetupE2EE';
@ -105,19 +107,28 @@ function VideoConferenceComponent(props: {
if (e2eeEnabled && (videoCodec === 'av1' || videoCodec === 'vp9')) {
videoCodec = undefined;
}
const videoCaptureDefaults: VideoCaptureOptions = {
deviceId: props.userChoices.videoDeviceId ?? undefined,
resolution: props.options.hq ? VideoPresets.h2160 : VideoPresets.h720,
};
const publishDefaults: TrackPublishDefaults = {
dtx: false,
videoSimulcastLayers: props.options.hq
? [VideoPresets.h1080, VideoPresets.h720]
: [VideoPresets.h540, VideoPresets.h216],
red: !e2eeEnabled,
videoCodec,
};
if (isLowPowerDevice()) {
// on lower end devices, publish at a lower resolution, and disable spatial layers
// encoding spatial layers adds to CPU overhead
videoCaptureDefaults.resolution = VideoPresets.h360;
publishDefaults.simulcast = false;
publishDefaults.scalabilityMode = 'L1T3';
}
return {
videoCaptureDefaults: {
deviceId: props.userChoices.videoDeviceId ?? undefined,
resolution: props.options.hq ? VideoPresets.h2160 : VideoPresets.h720,
},
publishDefaults: {
dtx: false,
videoSimulcastLayers: props.options.hq
? [VideoPresets.h1080, VideoPresets.h720]
: [VideoPresets.h540, VideoPresets.h216],
red: !e2eeEnabled,
videoCodec,
},
videoCaptureDefaults: videoCaptureDefaults,
publishDefaults: publishDefaults,
audioCaptureDefaults: {
deviceId: props.userChoices.audioDeviceId ?? undefined,
},

View File

@ -26,8 +26,8 @@ export function CameraSettings() {
(cameraTrack as LocalTrackPublication)?.track?.getProcessor()?.name === 'background-blur'
? 'blur'
: (cameraTrack as LocalTrackPublication)?.track?.getProcessor()?.name === 'virtual-background'
? 'image'
: 'none',
? 'image'
: 'none',
);
const [virtualBackgroundImagePath, setVirtualBackgroundImagePath] = React.useState<string | null>(

View File

@ -3,12 +3,16 @@ import { useKrispNoiseFilter } from '@livekit/components-react/krisp';
import { TrackToggle } from '@livekit/components-react';
import { MediaDeviceMenu } from '@livekit/components-react';
import { Track } from 'livekit-client';
import { isLowPowerDevice } from './client-utils';
export function MicrophoneSettings() {
const { isNoiseFilterEnabled, setNoiseFilterEnabled, isNoiseFilterPending } = useKrispNoiseFilter(
{
filterOptions: {
quality: 'high',
quality: isLowPowerDevice() ? 'low' : 'medium',
onBufferDrop: () => {
console.warn('krisp buffer dropped, either disable or reduce quality');
},
},
},
);

View File

@ -19,3 +19,7 @@ export function randomString(length: number): string {
}
return result;
}
export function isLowPowerDevice() {
return navigator.hardwareConcurrency < 6;
}

View File

@ -32,7 +32,8 @@
"eslint": "9.27.0",
"eslint-config-next": "15.3.2",
"source-map-loader": "^5.0.0",
"typescript": "5.8.3"
"typescript": "5.8.3",
"prettier": "3.5.3"
},
"engines": {
"node": ">=18"

10
pnpm-lock.yaml generated
View File

@ -60,6 +60,9 @@ importers:
eslint-config-next:
specifier: 15.3.2
version: 15.3.2(eslint@9.27.0)(typescript@5.8.3)
prettier:
specifier: 3.5.3
version: 3.5.3
source-map-loader:
specifier: ^5.0.0
version: 5.0.0(webpack@5.95.0)
@ -1458,6 +1461,11 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier@3.5.3:
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
engines: {node: '>=14'}
hasBin: true
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@ -3396,6 +3404,8 @@ snapshots:
prelude-ls@1.2.1: {}
prettier@3.5.3: {}
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0