diff --git a/app/rooms/[roomName]/PageClientImpl.tsx b/app/rooms/[roomName]/PageClientImpl.tsx index 3a88002..f4bfd8a 100644 --- a/app/rooms/[roomName]/PageClientImpl.tsx +++ b/app/rooms/[roomName]/PageClientImpl.tsx @@ -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, }, diff --git a/lib/CameraSettings.tsx b/lib/CameraSettings.tsx index fe448e6..37690d0 100644 --- a/lib/CameraSettings.tsx +++ b/lib/CameraSettings.tsx @@ -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( diff --git a/lib/MicrophoneSettings.tsx b/lib/MicrophoneSettings.tsx index e0f157c..c71bb4a 100644 --- a/lib/MicrophoneSettings.tsx +++ b/lib/MicrophoneSettings.tsx @@ -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'); + }, }, }, ); diff --git a/lib/client-utils.ts b/lib/client-utils.ts index b37257f..a742ae3 100644 --- a/lib/client-utils.ts +++ b/lib/client-utils.ts @@ -19,3 +19,7 @@ export function randomString(length: number): string { } return result; } + +export function isLowPowerDevice() { + return navigator.hardwareConcurrency < 6; +} diff --git a/package.json b/package.json index 745a1ab..a728d3d 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb766d2..75c0109 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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