refactor
- still should not work without a fixing upstream LK: https://github.com/livekit/components-js/pull/1042 https://github.com/livekit/components-js/pull/1043
This commit is contained in:
54
src/App.tsx
54
src/App.tsx
@@ -28,6 +28,7 @@ import { Initializer } from "./initializer";
|
|||||||
import { MediaDevicesProvider } from "./livekit/MediaDevicesContext";
|
import { MediaDevicesProvider } from "./livekit/MediaDevicesContext";
|
||||||
import { widget } from "./widget";
|
import { widget } from "./widget";
|
||||||
import { useTheme } from "./useTheme";
|
import { useTheme } from "./useTheme";
|
||||||
|
import { ProcessorProvider } from "./livekit/TrackProcessorContext";
|
||||||
|
|
||||||
const SentryRoute = Sentry.withSentryRouting(Route);
|
const SentryRoute = Sentry.withSentryRouting(Route);
|
||||||
|
|
||||||
@@ -82,27 +83,25 @@ export const App: FC<AppProps> = ({ history }) => {
|
|||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
{loaded ? (
|
{loaded ? (
|
||||||
<Suspense fallback={null}>
|
<Suspense fallback={null}>
|
||||||
<ClientProvider>
|
<Providers>
|
||||||
<MediaDevicesProvider>
|
<Sentry.ErrorBoundary fallback={errorPage}>
|
||||||
<Sentry.ErrorBoundary fallback={errorPage}>
|
<DisconnectedBanner />
|
||||||
<DisconnectedBanner />
|
<Switch>
|
||||||
<Switch>
|
<SentryRoute exact path="/">
|
||||||
<SentryRoute exact path="/">
|
<HomePage />
|
||||||
<HomePage />
|
</SentryRoute>
|
||||||
</SentryRoute>
|
<SentryRoute exact path="/login">
|
||||||
<SentryRoute exact path="/login">
|
<LoginPage />
|
||||||
<LoginPage />
|
</SentryRoute>
|
||||||
</SentryRoute>
|
<SentryRoute exact path="/register">
|
||||||
<SentryRoute exact path="/register">
|
<RegisterPage />
|
||||||
<RegisterPage />
|
</SentryRoute>
|
||||||
</SentryRoute>
|
<SentryRoute path="*">
|
||||||
<SentryRoute path="*">
|
<RoomPage />
|
||||||
<RoomPage />
|
</SentryRoute>
|
||||||
</SentryRoute>
|
</Switch>
|
||||||
</Switch>
|
</Sentry.ErrorBoundary>
|
||||||
</Sentry.ErrorBoundary>
|
</Providers>
|
||||||
</MediaDevicesProvider>
|
|
||||||
</ClientProvider>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
) : (
|
) : (
|
||||||
<LoadingView />
|
<LoadingView />
|
||||||
@@ -113,3 +112,16 @@ export const App: FC<AppProps> = ({ history }) => {
|
|||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Providers: FC<{
|
||||||
|
children: JSX.Element;
|
||||||
|
}> = ({ children }) => {
|
||||||
|
// We use this to stack all used providers to not make the App component to verbose
|
||||||
|
return (
|
||||||
|
<ClientProvider>
|
||||||
|
<MediaDevicesProvider>
|
||||||
|
<ProcessorProvider>{children}</ProcessorProvider>
|
||||||
|
</MediaDevicesProvider>
|
||||||
|
</ClientProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
111
src/livekit/TrackProcessorContext.tsx
Normal file
111
src/livekit/TrackProcessorContext.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2024 New Vector Ltd.
|
||||||
|
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
BackgroundBlur as backgroundBlur,
|
||||||
|
BackgroundOptions,
|
||||||
|
ProcessorWrapper,
|
||||||
|
} from "@livekit/track-processors";
|
||||||
|
import {
|
||||||
|
createContext,
|
||||||
|
FC,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { LocalVideoTrack } from "livekit-client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
backgroundBlur as backgroundBlurSettings,
|
||||||
|
useSetting,
|
||||||
|
} from "../settings/settings";
|
||||||
|
|
||||||
|
type ProcessorState = {
|
||||||
|
supported: boolean | undefined;
|
||||||
|
processor: undefined | ProcessorWrapper<BackgroundOptions>;
|
||||||
|
/**
|
||||||
|
* Call this method to try to initialize a processor.
|
||||||
|
* This only needs to happen if supported is undefined.
|
||||||
|
* If the backgroundBlur setting is set to true this does not need to be called
|
||||||
|
* and the processorState.supported will update automatically to the correct value.
|
||||||
|
*/
|
||||||
|
checkSupported: () => void;
|
||||||
|
};
|
||||||
|
const ProcessorContext = createContext<ProcessorState | undefined>(undefined);
|
||||||
|
|
||||||
|
export const useTrackProcessor = (): ProcessorState | undefined =>
|
||||||
|
useContext(ProcessorContext);
|
||||||
|
|
||||||
|
export const useTrackProcessorSync = (
|
||||||
|
videoTrack: LocalVideoTrack | null,
|
||||||
|
): void => {
|
||||||
|
const { processor } = useTrackProcessor() || {};
|
||||||
|
useEffect(() => {
|
||||||
|
if (processor && !videoTrack?.getProcessor()) {
|
||||||
|
void videoTrack?.setProcessor(processor);
|
||||||
|
}
|
||||||
|
if (!processor && videoTrack?.getProcessor()) {
|
||||||
|
void videoTrack?.stopProcessor();
|
||||||
|
}
|
||||||
|
}, [processor, videoTrack]);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: JSX.Element;
|
||||||
|
}
|
||||||
|
export const ProcessorProvider: FC<Props> = ({ children }) => {
|
||||||
|
// The setting the user wants to have
|
||||||
|
const [blurActivated] = useSetting(backgroundBlurSettings);
|
||||||
|
|
||||||
|
// If `ProcessorState.supported` is undefined the user can activate that we want
|
||||||
|
// to have it at least checked (this is useful to show the settings menu properly)
|
||||||
|
// We dont want to try initializing the blur if the user is not even looking at the setting
|
||||||
|
const [shouldCheckSupport, setShouldCheckSupport] = useState(blurActivated);
|
||||||
|
|
||||||
|
// Cache the processor so we only need to initialize it once.
|
||||||
|
const blur = useRef<ProcessorWrapper<BackgroundOptions> | undefined>(
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
const checkSupported = useCallback(() => {
|
||||||
|
setShouldCheckSupport(true);
|
||||||
|
}, []);
|
||||||
|
// This is the actual state exposed through the context
|
||||||
|
const [processorState, setProcessorState] = useState<ProcessorState>(() => ({
|
||||||
|
supported: false,
|
||||||
|
processor: undefined,
|
||||||
|
checkSupported,
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!shouldCheckSupport) return;
|
||||||
|
try {
|
||||||
|
if (!blur.current) blur.current = backgroundBlur(15, { delegate: "GPU" });
|
||||||
|
setProcessorState({
|
||||||
|
checkSupported,
|
||||||
|
supported: true,
|
||||||
|
processor: blurActivated ? blur.current : undefined,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
setProcessorState({
|
||||||
|
checkSupported,
|
||||||
|
supported: false,
|
||||||
|
processor: undefined,
|
||||||
|
});
|
||||||
|
logger.error("disable background blur", e);
|
||||||
|
}
|
||||||
|
}, [blurActivated, checkSupported, shouldCheckSupport]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProcessorContext.Provider value={processorState}>
|
||||||
|
{children}
|
||||||
|
</ProcessorContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,9 +9,8 @@ import {
|
|||||||
ConnectionState,
|
ConnectionState,
|
||||||
E2EEOptions,
|
E2EEOptions,
|
||||||
ExternalE2EEKeyProvider,
|
ExternalE2EEKeyProvider,
|
||||||
LocalTrackPublication,
|
LocalVideoTrack,
|
||||||
Room,
|
Room,
|
||||||
RoomEvent,
|
|
||||||
RoomOptions,
|
RoomOptions,
|
||||||
Track,
|
Track,
|
||||||
} from "livekit-client";
|
} from "livekit-client";
|
||||||
@@ -19,7 +18,6 @@ import { useEffect, useMemo, useRef } from "react";
|
|||||||
import E2EEWorker from "livekit-client/e2ee-worker?worker";
|
import E2EEWorker from "livekit-client/e2ee-worker?worker";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||||
import { BackgroundBlur as backgroundBlur } from "@livekit/track-processors";
|
|
||||||
|
|
||||||
import { defaultLiveKitOptions } from "./options";
|
import { defaultLiveKitOptions } from "./options";
|
||||||
import { SFUConfig } from "./openIDSFU";
|
import { SFUConfig } from "./openIDSFU";
|
||||||
@@ -29,7 +27,6 @@ import {
|
|||||||
MediaDevices,
|
MediaDevices,
|
||||||
useMediaDevices,
|
useMediaDevices,
|
||||||
} from "./MediaDevicesContext";
|
} from "./MediaDevicesContext";
|
||||||
import { backgroundBlur as backgroundBlurSettings } from "../settings/settings";
|
|
||||||
import {
|
import {
|
||||||
ECConnectionState,
|
ECConnectionState,
|
||||||
useECConnectionState,
|
useECConnectionState,
|
||||||
@@ -37,7 +34,11 @@ import {
|
|||||||
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
|
import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider";
|
||||||
import { E2eeType } from "../e2ee/e2eeType";
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
import { EncryptionSystem } from "../e2ee/sharedKeyManagement";
|
||||||
import { useSetting } from "../settings/settings";
|
import {
|
||||||
|
useTrackProcessor,
|
||||||
|
useTrackProcessorSync,
|
||||||
|
} from "./TrackProcessorContext";
|
||||||
|
import { useInitial } from "../useInitial";
|
||||||
|
|
||||||
interface UseLivekitResult {
|
interface UseLivekitResult {
|
||||||
livekitRoom?: Room;
|
livekitRoom?: Room;
|
||||||
@@ -83,22 +84,16 @@ export function useLiveKit(
|
|||||||
const initialMuteStates = useRef<MuteStates>(muteStates);
|
const initialMuteStates = useRef<MuteStates>(muteStates);
|
||||||
const devices = useMediaDevices();
|
const devices = useMediaDevices();
|
||||||
const initialDevices = useRef<MediaDevices>(devices);
|
const initialDevices = useRef<MediaDevices>(devices);
|
||||||
const blur = useMemo(() => {
|
|
||||||
let b = undefined;
|
const { processor } = useTrackProcessor() || {};
|
||||||
try {
|
const initialProcessor = useInitial(() => processor);
|
||||||
b = backgroundBlur(15, { delegate: "GPU" });
|
|
||||||
} catch (e) {
|
|
||||||
logger.error("disable background blur", e);
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}, []);
|
|
||||||
const roomOptions = useMemo(
|
const roomOptions = useMemo(
|
||||||
(): RoomOptions => ({
|
(): RoomOptions => ({
|
||||||
...defaultLiveKitOptions,
|
...defaultLiveKitOptions,
|
||||||
videoCaptureDefaults: {
|
videoCaptureDefaults: {
|
||||||
...defaultLiveKitOptions.videoCaptureDefaults,
|
...defaultLiveKitOptions.videoCaptureDefaults,
|
||||||
deviceId: initialDevices.current.videoInput.selectedId,
|
deviceId: initialDevices.current.videoInput.selectedId,
|
||||||
processor: blur,
|
processor: initialProcessor,
|
||||||
},
|
},
|
||||||
audioCaptureDefaults: {
|
audioCaptureDefaults: {
|
||||||
...defaultLiveKitOptions.audioCaptureDefaults,
|
...defaultLiveKitOptions.audioCaptureDefaults,
|
||||||
@@ -109,7 +104,7 @@ export function useLiveKit(
|
|||||||
},
|
},
|
||||||
e2ee: e2eeOptions,
|
e2ee: e2eeOptions,
|
||||||
}),
|
}),
|
||||||
[blur, e2eeOptions],
|
[e2eeOptions, initialProcessor],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store if audio/video are currently updating. If to prohibit unnecessary calls
|
// Store if audio/video are currently updating. If to prohibit unnecessary calls
|
||||||
@@ -134,6 +129,15 @@ export function useLiveKit(
|
|||||||
return r;
|
return r;
|
||||||
}, [roomOptions, e2eeSystem]);
|
}, [roomOptions, e2eeSystem]);
|
||||||
|
|
||||||
|
const videoTrack = useMemo(
|
||||||
|
() =>
|
||||||
|
Array.from(room.localParticipant.videoTrackPublications.values()).find(
|
||||||
|
(v) => v.source === Track.Source.Camera,
|
||||||
|
)?.track as LocalVideoTrack | null,
|
||||||
|
[room.localParticipant.videoTrackPublications],
|
||||||
|
);
|
||||||
|
useTrackProcessorSync(videoTrack);
|
||||||
|
|
||||||
const connectionState = useECConnectionState(
|
const connectionState = useECConnectionState(
|
||||||
{
|
{
|
||||||
deviceId: initialDevices.current.audioInput.selectedId,
|
deviceId: initialDevices.current.audioInput.selectedId,
|
||||||
@@ -143,58 +147,6 @@ export function useLiveKit(
|
|||||||
sfuConfig,
|
sfuConfig,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [showBackgroundBlur] = useSetting(backgroundBlurSettings);
|
|
||||||
const videoTrackPromise = useRef<
|
|
||||||
undefined | Promise<LocalTrackPublication | undefined>
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Don't even try if we cannot blur on this platform
|
|
||||||
if (!blur) return;
|
|
||||||
if (!room || videoTrackPromise.current) return;
|
|
||||||
const update = async (): Promise<void> => {
|
|
||||||
let publishCallback: undefined | ((track: LocalTrackPublication) => void);
|
|
||||||
videoTrackPromise.current = new Promise<
|
|
||||||
LocalTrackPublication | undefined
|
|
||||||
>((resolve) => {
|
|
||||||
const videoTrack = Array.from(
|
|
||||||
room.localParticipant.videoTrackPublications.values(),
|
|
||||||
).find((v) => v.source === Track.Source.Camera);
|
|
||||||
if (videoTrack) {
|
|
||||||
resolve(videoTrack);
|
|
||||||
}
|
|
||||||
publishCallback = (videoTrack: LocalTrackPublication): void => {
|
|
||||||
if (videoTrack.source === Track.Source.Camera) {
|
|
||||||
resolve(videoTrack);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
room.on(RoomEvent.LocalTrackPublished, publishCallback);
|
|
||||||
});
|
|
||||||
|
|
||||||
const videoTrack = await videoTrackPromise.current;
|
|
||||||
|
|
||||||
if (publishCallback)
|
|
||||||
room.off(RoomEvent.LocalTrackPublished, publishCallback);
|
|
||||||
|
|
||||||
if (videoTrack !== undefined) {
|
|
||||||
if (
|
|
||||||
showBackgroundBlur &&
|
|
||||||
videoTrack.track?.getProcessor()?.name !== "background-blur"
|
|
||||||
) {
|
|
||||||
logger.info("Blur: set blur");
|
|
||||||
|
|
||||||
void videoTrack.track?.setProcessor(blur);
|
|
||||||
} else if (
|
|
||||||
videoTrack.track?.getProcessor()?.name === "background-blur"
|
|
||||||
) {
|
|
||||||
void videoTrack.track?.stopProcessor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
videoTrackPromise.current = undefined;
|
|
||||||
};
|
|
||||||
void update();
|
|
||||||
}, [blur, room, showBackgroundBlur]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Sync the requested mute states with LiveKit's mute states. We do it this
|
// Sync the requested mute states with LiveKit's mute states. We do it this
|
||||||
// way around rather than using LiveKit as the source of truth, so that the
|
// way around rather than using LiveKit as the source of truth, so that the
|
||||||
@@ -261,6 +213,7 @@ export function useLiveKit(
|
|||||||
audioMuteUpdating.current = true;
|
audioMuteUpdating.current = true;
|
||||||
trackPublication = await participant.setMicrophoneEnabled(
|
trackPublication = await participant.setMicrophoneEnabled(
|
||||||
buttonEnabled.current.audio,
|
buttonEnabled.current.audio,
|
||||||
|
room.options.audioCaptureDefaults,
|
||||||
);
|
);
|
||||||
audioMuteUpdating.current = false;
|
audioMuteUpdating.current = false;
|
||||||
break;
|
break;
|
||||||
@@ -268,6 +221,7 @@ export function useLiveKit(
|
|||||||
videoMuteUpdating.current = true;
|
videoMuteUpdating.current = true;
|
||||||
trackPublication = await participant.setCameraEnabled(
|
trackPublication = await participant.setCameraEnabled(
|
||||||
buttonEnabled.current.video,
|
buttonEnabled.current.video,
|
||||||
|
room.options.videoCaptureDefaults,
|
||||||
);
|
);
|
||||||
videoMuteUpdating.current = false;
|
videoMuteUpdating.current = false;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -13,10 +13,13 @@ import classNames from "classnames";
|
|||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { usePreviewTracks } from "@livekit/components-react";
|
import { usePreviewTracks } from "@livekit/components-react";
|
||||||
import { LocalVideoTrack, Track } from "livekit-client";
|
import {
|
||||||
|
CreateLocalTracksOptions,
|
||||||
|
LocalVideoTrack,
|
||||||
|
Track,
|
||||||
|
} from "livekit-client";
|
||||||
import { useObservable } from "observable-hooks";
|
import { useObservable } from "observable-hooks";
|
||||||
import { map } from "rxjs";
|
import { map } from "rxjs";
|
||||||
import { BackgroundBlur as backgroundBlur } from "@livekit/track-processors";
|
|
||||||
|
|
||||||
import inCallStyles from "./InCallView.module.css";
|
import inCallStyles from "./InCallView.module.css";
|
||||||
import styles from "./LobbyView.module.css";
|
import styles from "./LobbyView.module.css";
|
||||||
@@ -33,14 +36,16 @@ import {
|
|||||||
VideoButton,
|
VideoButton,
|
||||||
} from "../button/Button";
|
} from "../button/Button";
|
||||||
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
|
import { SettingsModal, defaultSettingsTab } from "../settings/SettingsModal";
|
||||||
import { backgroundBlur as backgroundBlurSettings } from "../settings/settings";
|
|
||||||
import { useMediaQuery } from "../useMediaQuery";
|
import { useMediaQuery } from "../useMediaQuery";
|
||||||
import { E2eeType } from "../e2ee/e2eeType";
|
import { E2eeType } from "../e2ee/e2eeType";
|
||||||
import { Link } from "../button/Link";
|
import { Link } from "../button/Link";
|
||||||
import { useMediaDevices } from "../livekit/MediaDevicesContext";
|
import { useMediaDevices } from "../livekit/MediaDevicesContext";
|
||||||
import { useInitial } from "../useInitial";
|
import { useInitial } from "../useInitial";
|
||||||
import { useSwitchCamera as useShowSwitchCamera } from "./useSwitchCamera";
|
import { useSwitchCamera as useShowSwitchCamera } from "./useSwitchCamera";
|
||||||
import { useSetting } from "../settings/settings";
|
import {
|
||||||
|
useTrackProcessor,
|
||||||
|
useTrackProcessorSync,
|
||||||
|
} from "../livekit/TrackProcessorContext";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
client: MatrixClient;
|
client: MatrixClient;
|
||||||
@@ -111,20 +116,10 @@ export const LobbyView: FC<Props> = ({
|
|||||||
muteStates.audio.enabled && { deviceId: devices.audioInput.selectedId },
|
muteStates.audio.enabled && { deviceId: devices.audioInput.selectedId },
|
||||||
);
|
);
|
||||||
|
|
||||||
const blur = useMemo(() => {
|
const { processor } = useTrackProcessor() || {};
|
||||||
let b = undefined;
|
|
||||||
try {
|
|
||||||
b = backgroundBlur(15, { delegate: "GPU" });
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(
|
|
||||||
"disable background blur because its not supported by the platform.",
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const localTrackOptions = useMemo(
|
const initialProcessor = useInitial(() => processor);
|
||||||
|
const localTrackOptions = useMemo<CreateLocalTracksOptions>(
|
||||||
() => ({
|
() => ({
|
||||||
// The only reason we request audio here is to get the audio permission
|
// The only reason we request audio here is to get the audio permission
|
||||||
// request over with at the same time. But changing the audio settings
|
// request over with at the same time. But changing the audio settings
|
||||||
@@ -135,14 +130,14 @@ export const LobbyView: FC<Props> = ({
|
|||||||
audio: Object.assign({}, initialAudioOptions),
|
audio: Object.assign({}, initialAudioOptions),
|
||||||
video: muteStates.video.enabled && {
|
video: muteStates.video.enabled && {
|
||||||
deviceId: devices.videoInput.selectedId,
|
deviceId: devices.videoInput.selectedId,
|
||||||
// It should be possible to set a processor here:
|
processor: initialProcessor,
|
||||||
// processor: blur,
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
initialAudioOptions,
|
initialAudioOptions,
|
||||||
muteStates.video.enabled,
|
muteStates.video.enabled,
|
||||||
devices.videoInput.selectedId,
|
devices.videoInput.selectedId,
|
||||||
|
initialProcessor,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -157,28 +152,11 @@ export const LobbyView: FC<Props> = ({
|
|||||||
|
|
||||||
const tracks = usePreviewTracks(localTrackOptions, onError);
|
const tracks = usePreviewTracks(localTrackOptions, onError);
|
||||||
|
|
||||||
const videoTrack = useMemo(
|
const videoTrack = useMemo(() => {
|
||||||
() =>
|
const track = tracks?.find((t) => t.kind === Track.Kind.Video);
|
||||||
(tracks?.find((t) => t.kind === Track.Kind.Video) ??
|
return track as LocalVideoTrack | null;
|
||||||
null) as LocalVideoTrack | null,
|
}, [tracks]);
|
||||||
[tracks],
|
useTrackProcessorSync(videoTrack);
|
||||||
);
|
|
||||||
|
|
||||||
const [showBackgroundBlur] = useSetting(backgroundBlurSettings);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Fon't even try if we cannot blur on this platform
|
|
||||||
if (!blur) return;
|
|
||||||
const updateBlur = async (showBlur: boolean): Promise<void> => {
|
|
||||||
if (showBlur && !videoTrack?.getProcessor()) {
|
|
||||||
await videoTrack?.setProcessor(blur);
|
|
||||||
} else {
|
|
||||||
await videoTrack?.stopProcessor();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (videoTrack) void updateBlur(showBackgroundBlur);
|
|
||||||
}, [videoTrack, showBackgroundBlur, blur]);
|
|
||||||
|
|
||||||
const showSwitchCamera = useShowSwitchCamera(
|
const showSwitchCamera = useShowSwitchCamera(
|
||||||
useObservable(
|
useObservable(
|
||||||
(inputs) => inputs.pipe(map(([video]) => video)),
|
(inputs) => inputs.pipe(map(([video]) => video)),
|
||||||
|
|||||||
@@ -5,12 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
Please see LICENSE in the repository root for full details.
|
Please see LICENSE in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ChangeEvent, FC, ReactNode, useCallback, useState } from "react";
|
import { ChangeEvent, FC, ReactNode, useCallback, useEffect, useState } from "react";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { Root as Form, Separator, Text } from "@vector-im/compound-web";
|
import { Root as Form, Separator, Text } from "@vector-im/compound-web";
|
||||||
import { BackgroundBlur as backgroundBlur } from "@livekit/track-processors";
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
|
||||||
|
|
||||||
import { Modal } from "../Modal";
|
import { Modal } from "../Modal";
|
||||||
import styles from "./SettingsModal.module.css";
|
import styles from "./SettingsModal.module.css";
|
||||||
@@ -36,6 +34,7 @@ import { isFirefox } from "../Platform";
|
|||||||
import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
|
import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
|
||||||
import { Slider } from "../Slider";
|
import { Slider } from "../Slider";
|
||||||
import { DeviceSelection } from "./DeviceSelection";
|
import { DeviceSelection } from "./DeviceSelection";
|
||||||
|
import { useTrackProcessor } from "../livekit/TrackProcessorContext";
|
||||||
|
|
||||||
type SettingsTab =
|
type SettingsTab =
|
||||||
| "audio"
|
| "audio"
|
||||||
@@ -75,18 +74,11 @@ export const SettingsModal: FC<Props> = ({
|
|||||||
|
|
||||||
// Generate a `Checkbox` input to turn blur on or off.
|
// Generate a `Checkbox` input to turn blur on or off.
|
||||||
const BlurCheckbox: React.FC = (): ReactNode => {
|
const BlurCheckbox: React.FC = (): ReactNode => {
|
||||||
const [blur, setBlur] = useSetting(backgroundBlurSetting);
|
const { supported, checkSupported } = useTrackProcessor() || {};
|
||||||
let canBlur = true;
|
useEffect(() => checkSupported?.(), [checkSupported]);
|
||||||
try {
|
|
||||||
backgroundBlur(15);
|
const [blurActive, setBlurActive] = useSetting(backgroundBlurSetting);
|
||||||
} catch (e) {
|
|
||||||
logger.debug(
|
|
||||||
"Cannot blur, so we do not show the option in settings. error: ",
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
canBlur = false;
|
|
||||||
setBlur(false);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h4>{t("settings.background_blur_header")}</h4>
|
<h4>{t("settings.background_blur_header")}</h4>
|
||||||
@@ -96,12 +88,12 @@ export const SettingsModal: FC<Props> = ({
|
|||||||
id="activateBackgroundBlur"
|
id="activateBackgroundBlur"
|
||||||
label={t("settings.background_blur_label")}
|
label={t("settings.background_blur_label")}
|
||||||
description={
|
description={
|
||||||
canBlur ? "" : t("settings.blur_not_supported_by_browser")
|
supported ? "" : t("settings.blur_not_supported_by_browser")
|
||||||
}
|
}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={blur}
|
checked={!!blurActive}
|
||||||
onChange={(b): void => setBlur(b.target.checked)}
|
onChange={(b): void => setBlurActive(b.target.checked)}
|
||||||
disabled={!canBlur}
|
disabled={!supported}
|
||||||
/>
|
/>
|
||||||
</FieldRow>
|
</FieldRow>
|
||||||
</>
|
</>
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@@ -1805,10 +1805,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@livekit/mutex/-/mutex-1.0.0.tgz#9493102d92ff75dfb0445eccc46c7c7ac189d385"
|
resolved "https://registry.yarnpkg.com/@livekit/mutex/-/mutex-1.0.0.tgz#9493102d92ff75dfb0445eccc46c7c7ac189d385"
|
||||||
integrity sha512-aiUhoThBNF9UyGTxEURFzJLhhPLIVTnQiEVMjRhPnfHNKLfo2JY9xovHKIus7B78UD5hsP6DlgpmAsjrz4U0Iw==
|
integrity sha512-aiUhoThBNF9UyGTxEURFzJLhhPLIVTnQiEVMjRhPnfHNKLfo2JY9xovHKIus7B78UD5hsP6DlgpmAsjrz4U0Iw==
|
||||||
|
|
||||||
"@livekit/protocol@1.24.0":
|
"@livekit/protocol@1.29.3":
|
||||||
version "1.24.0"
|
version "1.29.3"
|
||||||
resolved "https://registry.yarnpkg.com/@livekit/protocol/-/protocol-1.24.0.tgz#b23acab25c11027bf26c1b42f9b782682f2da585"
|
resolved "https://registry.yarnpkg.com/@livekit/protocol/-/protocol-1.29.3.tgz#486ce215c0c591ad64036d9b13c7e28f5417cf03"
|
||||||
integrity sha512-9dCsqnkMn7lvbI4NGh18zhLDsrXyUcpS++TEFgEk5Xv1WM3R2kT3EzqgL1P/mr3jaabM6rJ8wZA/KJLuQNpF5w==
|
integrity sha512-5La/pm2LsSeCbm7xNe/TvHGYu7uVwDpLrlycpgo5nzofGq/TH67255vS8ni/1Y7vrFuAI8VYG/s42mcC1UF6tQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@bufbuild/protobuf" "^1.10.0"
|
"@bufbuild/protobuf" "^1.10.0"
|
||||||
|
|
||||||
@@ -6125,12 +6125,12 @@ lines-and-columns@^1.1.6:
|
|||||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||||
|
|
||||||
livekit-client@^2.5.7:
|
livekit-client@^2.5.7:
|
||||||
version "2.7.0"
|
version "2.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-2.7.0.tgz#d7a80aff4ad335dd093b0c90d0d715466539651a"
|
resolved "https://registry.yarnpkg.com/livekit-client/-/livekit-client-2.7.3.tgz#70a5f5016f3f50b1282f4b9090aa17a39f8bde09"
|
||||||
integrity sha512-4vjfSReFNAUD+2oLUz9qFRWztJaI/+AexpOmCgizNsPYpvvqgAvEGxapnhuAug9uP7JVYaKPXaTCq90MWZoDHg==
|
integrity sha512-oHEmUTFjIJARi5R87PsobZx8y2HCSUwla3Nu71EqDOAMnNY9aoGMLsJVao5Y+v1TSk71rgRm991fihgxtbg5xw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@livekit/mutex" "1.0.0"
|
"@livekit/mutex" "1.0.0"
|
||||||
"@livekit/protocol" "1.24.0"
|
"@livekit/protocol" "1.29.3"
|
||||||
events "^3.3.0"
|
events "^3.3.0"
|
||||||
loglevel "^1.8.0"
|
loglevel "^1.8.0"
|
||||||
sdp-transform "^2.14.1"
|
sdp-transform "^2.14.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user