diff --git a/knip.ts b/knip.ts index becafc2e9..5ffe03c45 100644 --- a/knip.ts +++ b/knip.ts @@ -24,6 +24,10 @@ export default { // then Knip will flag it as a false positive // https://github.com/webpro-nl/knip/issues/766 "@vector-im/compound-web", + // We need this so the eslint is happy with @livekit/track-processors. + // This might be a bug in the livekit repo but for now we fix it on the + // element call side. + "@types/dom-mediacapture-transform", "matrix-widget-api", ], ignoreExportsUsedInFile: true, diff --git a/locales/en/app.json b/locales/en/app.json index a47e5bebe..7af8040fb 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -150,6 +150,9 @@ "effect_volume_description": "Adjust the volume at which reactions and hand raised effects play.", "effect_volume_label": "Sound effect volume" }, + "background_blur_header": "Background", + "background_blur_label": "Blur the background of the video", + "blur_not_supported_by_browser": "(Background blur is not supported by this device)", "developer_tab_title": "Developer", "devices": { "camera": "Camera", diff --git a/package.json b/package.json index 4649ee9cd..6d0f2d0e1 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,8 @@ "@formatjs/intl-segmenter": "^11.7.3", "@livekit/components-core": "^0.11.0", "@livekit/components-react": "^2.0.0", + "@livekit/track-processors": "^0.3.2", + "@mediapipe/tasks-vision": "^0.10.18", "@opentelemetry/api": "^1.4.0", "@opentelemetry/core": "^1.25.1", "@opentelemetry/exporter-trace-otlp-http": "^0.56.0", @@ -50,6 +52,7 @@ "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.5.1", "@types/content-type": "^1.1.5", + "@types/dom-mediacapture-transform": "^0.1.10", "@types/grecaptcha": "^3.0.9", "@types/jsdom": "^21.1.7", "@types/lodash-es": "^4.17.12", diff --git a/src/App.tsx b/src/App.tsx index 288d4c9d9..3200b8859 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -28,6 +28,7 @@ import { Initializer } from "./initializer"; import { MediaDevicesProvider } from "./livekit/MediaDevicesContext"; import { widget } from "./widget"; import { useTheme } from "./useTheme"; +import { ProcessorProvider } from "./livekit/TrackProcessorContext"; const SentryRoute = Sentry.withSentryRouting(Route); @@ -82,27 +83,25 @@ export const App: FC = ({ history }) => { {loaded ? ( - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + ) : ( @@ -113,3 +112,16 @@ export const App: FC = ({ history }) => { ); }; + +const Providers: FC<{ + children: JSX.Element; +}> = ({ children }) => { + // We use this to stack all used providers to not make the App component to verbose + return ( + + + {children} + + + ); +}; diff --git a/src/livekit/BlurBackgroundTransformer.ts b/src/livekit/BlurBackgroundTransformer.ts new file mode 100644 index 000000000..51b6a5363 --- /dev/null +++ b/src/livekit/BlurBackgroundTransformer.ts @@ -0,0 +1,62 @@ +/* +Copyright 2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only +Please see LICENSE in the repository root for full details. +*/ + +import { + BackgroundTransformer, + VideoTransformer, + type VideoTransformerInitOptions, +} from "@livekit/track-processors"; +import { ImageSegmenter } from "@mediapipe/tasks-vision"; + +interface WasmFileset { + /** The path to the Wasm loader script. */ + wasmLoaderPath: string; + /** The path to the Wasm binary. */ + wasmBinaryPath: string; +} + +// n.b. this only includes the SIMD versions of the WASM files which have good support: +// https://caniuse.com/?search=simd +const wasmFileset: WasmFileset = { + wasmLoaderPath: new URL( + "../../node_modules/@mediapipe/tasks-vision/wasm/vision_wasm_internal.js", + import.meta.url, + ).href, + wasmBinaryPath: new URL( + "../../node_modules/@mediapipe/tasks-vision/wasm/vision_wasm_internal.wasm", + import.meta.url, + ).href, +}; + +const modelAssetPath = new URL( + "../mediapipe/imageSegmenter/selfie_segmenter.tflite", + import.meta.url, +).href; + +export class BlurBackgroundTransformer extends BackgroundTransformer { + public async init({ + outputCanvas, + inputElement: inputVideo, + }: VideoTransformerInitOptions): Promise { + // call super.super.init() + await VideoTransformer.prototype.init.call(this, { + outputCanvas, + inputElement: inputVideo, + }); + + this.imageSegmenter = await ImageSegmenter.createFromOptions(wasmFileset, { + baseOptions: { + modelAssetPath, + delegate: "GPU", + ...this.options.segmenterOptions, + }, + runningMode: "VIDEO", + outputCategoryMask: true, + outputConfidenceMasks: false, + }); + } +} diff --git a/src/livekit/TrackProcessorContext.tsx b/src/livekit/TrackProcessorContext.tsx new file mode 100644 index 000000000..1fc0005ad --- /dev/null +++ b/src/livekit/TrackProcessorContext.tsx @@ -0,0 +1,122 @@ +/* +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, + type ProcessorWrapper, + type BackgroundOptions, +} from "@livekit/track-processors"; +import { + createContext, + type FC, + useCallback, + useContext, + useEffect, + useRef, + useState, +} from "react"; +import { logger } from "matrix-js-sdk/src/logger"; +import { type LocalVideoTrack } from "livekit-client"; + +import { + backgroundBlur as backgroundBlurSettings, + useSetting, +} from "../settings/settings"; + +type ProcessorState = { + supported: boolean | undefined; + processor: undefined | ProcessorWrapper; + /** + * 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(undefined); + +export const useTrackProcessor = (): ProcessorState | undefined => + useContext(ProcessorContext); + +export const useTrackProcessorSync = ( + videoTrack: LocalVideoTrack | null, +): void => { + const { processor } = useTrackProcessor() || {}; + useEffect(() => { + if (!videoTrack) return; + 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 = ({ 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 | undefined>( + undefined, + ); + + const checkSupported = useCallback(() => { + setShouldCheckSupport(true); + }, []); + // This is the actual state exposed through the context + const [processorState, setProcessorState] = useState(() => ({ + supported: false, + processor: undefined, + checkSupported, + })); + + useEffect(() => { + if (!shouldCheckSupport) return; + try { + if (!blur.current) { + // TODO: move to our own local version of the transformer. + // Currently this is broken: error when trying to pipe IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number. + // blur.current = new ProcessorWrapper( + // new BlurBackgroundTransformer({}), + // "background-blur", + // ); + + // eslint-disable-next-line new-cap + blur.current = backgroundBlur(); + } + 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 ( + + {children} + + ); +}; diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index 41b305e53..aca6ed921 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -9,6 +9,7 @@ import { ConnectionState, type E2EEManagerOptions, ExternalE2EEKeyProvider, + type LocalVideoTrack, Room, type RoomOptions, Track, @@ -33,6 +34,11 @@ import { import { MatrixKeyProvider } from "../e2ee/matrixKeyProvider"; import { E2eeType } from "../e2ee/e2eeType"; import { type EncryptionSystem } from "../e2ee/sharedKeyManagement"; +import { + useTrackProcessor, + useTrackProcessorSync, +} from "./TrackProcessorContext"; +import { useInitial } from "../useInitial"; interface UseLivekitResult { livekitRoom?: Room; @@ -79,12 +85,15 @@ export function useLiveKit( const devices = useMediaDevices(); const initialDevices = useRef(devices); + const { processor } = useTrackProcessor() || {}; + const initialProcessor = useInitial(() => processor); const roomOptions = useMemo( (): RoomOptions => ({ ...defaultLiveKitOptions, videoCaptureDefaults: { ...defaultLiveKitOptions.videoCaptureDefaults, deviceId: initialDevices.current.videoInput.selectedId, + processor: initialProcessor, }, audioCaptureDefaults: { ...defaultLiveKitOptions.audioCaptureDefaults, @@ -95,7 +104,7 @@ export function useLiveKit( }, e2ee: e2eeOptions, }), - [e2eeOptions], + [e2eeOptions, initialProcessor], ); // Store if audio/video are currently updating. If to prohibit unnecessary calls @@ -120,6 +129,21 @@ export function useLiveKit( return r; }, [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, + // We need to update on map changes + // eslint-disable-next-line react-hooks/exhaustive-deps + room.localParticipant.videoTrackPublications.keys(), + ], + ); + + useTrackProcessorSync(videoTrack); + const connectionState = useECConnectionState( { deviceId: initialDevices.current.audioInput.selectedId, @@ -195,6 +219,7 @@ export function useLiveKit( audioMuteUpdating.current = true; trackPublication = await participant.setMicrophoneEnabled( buttonEnabled.current.audio, + room.options.audioCaptureDefaults, ); audioMuteUpdating.current = false; break; @@ -202,6 +227,7 @@ export function useLiveKit( videoMuteUpdating.current = true; trackPublication = await participant.setCameraEnabled( buttonEnabled.current.video, + room.options.videoCaptureDefaults, ); videoMuteUpdating.current = false; break; diff --git a/src/mediapipe/imageSegmenter/README.md b/src/mediapipe/imageSegmenter/README.md new file mode 100644 index 000000000..39bea2d81 --- /dev/null +++ b/src/mediapipe/imageSegmenter/README.md @@ -0,0 +1,5 @@ +# Google AI Edge MediaPipe Selfie Segmentation + +- See: https://ai.google.dev/edge/mediapipe/solutions/vision/image_segmenter +- Latest: https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_segmenter/float16/latest/selfie_segmenter.tflite +- License: Apache 2.0 as per https://storage.googleapis.com/mediapipe-assets/Model%20Card%20MediaPipe%20Selfie%20Segmentation.pdf diff --git a/src/mediapipe/imageSegmenter/selfie_segmenter.tflite b/src/mediapipe/imageSegmenter/selfie_segmenter.tflite new file mode 100644 index 000000000..a4ebd4777 Binary files /dev/null and b/src/mediapipe/imageSegmenter/selfie_segmenter.tflite differ diff --git a/src/room/LobbyView.tsx b/src/room/LobbyView.tsx index 4622cd3e4..15b7a7743 100644 --- a/src/room/LobbyView.tsx +++ b/src/room/LobbyView.tsx @@ -13,7 +13,11 @@ import classNames from "classnames"; import { useHistory } from "react-router-dom"; import { logger } from "matrix-js-sdk/src/logger"; import { usePreviewTracks } from "@livekit/components-react"; -import { type LocalVideoTrack, Track } from "livekit-client"; +import { + type CreateLocalTracksOptions, + type LocalVideoTrack, + Track, +} from "livekit-client"; import { useObservable } from "observable-hooks"; import { map } from "rxjs"; @@ -37,7 +41,11 @@ import { E2eeType } from "../e2ee/e2eeType"; import { Link } from "../button/Link"; import { useMediaDevices } from "../livekit/MediaDevicesContext"; import { useInitial } from "../useInitial"; -import { useSwitchCamera } from "./useSwitchCamera"; +import { useSwitchCamera as useShowSwitchCamera } from "./useSwitchCamera"; +import { + useTrackProcessor, + useTrackProcessorSync, +} from "../livekit/TrackProcessorContext"; interface Props { client: MatrixClient; @@ -108,7 +116,10 @@ export const LobbyView: FC = ({ muteStates.audio.enabled && { deviceId: devices.audioInput.selectedId }, ); - const localTrackOptions = useMemo( + const { processor } = useTrackProcessor() || {}; + + const initialProcessor = useInitial(() => processor); + const localTrackOptions = useMemo( () => ({ // 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 @@ -119,12 +130,14 @@ export const LobbyView: FC = ({ audio: Object.assign({}, initialAudioOptions), video: muteStates.video.enabled && { deviceId: devices.videoInput.selectedId, + processor: initialProcessor, }, }), [ initialAudioOptions, - devices.videoInput.selectedId, muteStates.video.enabled, + devices.videoInput.selectedId, + initialProcessor, ], ); @@ -139,14 +152,12 @@ export const LobbyView: FC = ({ const tracks = usePreviewTracks(localTrackOptions, onError); - const videoTrack = useMemo( - () => - (tracks?.find((t) => t.kind === Track.Kind.Video) ?? - null) as LocalVideoTrack | null, - [tracks], - ); - - const switchCamera = useSwitchCamera( + const videoTrack = useMemo(() => { + const track = tracks?.find((t) => t.kind === Track.Kind.Video); + return track as LocalVideoTrack | null; + }, [tracks]); + useTrackProcessorSync(videoTrack); + const showSwitchCamera = useShowSwitchCamera( useObservable( (inputs$) => inputs$.pipe(map(([video]) => video)), [videoTrack], @@ -208,7 +219,9 @@ export const LobbyView: FC = ({ onClick={onVideoPress} disabled={muteStates.video.setEnabled === null} /> - {switchCamera && } + {showSwitchCamera && ( + + )} {!confineToRoom && } diff --git a/src/settings/SettingsModal.tsx b/src/settings/SettingsModal.tsx index b70660953..fa51be529 100644 --- a/src/settings/SettingsModal.tsx +++ b/src/settings/SettingsModal.tsx @@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { type FC, useState } from "react"; +import { type FC, type ReactNode, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { type MatrixClient } from "matrix-js-sdk/src/matrix"; -import { Root as Form } from "@vector-im/compound-web"; +import { Root as Form, Separator } from "@vector-im/compound-web"; import { Modal } from "../Modal"; import styles from "./SettingsModal.module.css"; @@ -23,12 +23,15 @@ import { widget } from "../widget"; import { useSetting, soundEffectVolumeSetting, + backgroundBlur as backgroundBlurSetting, developerMode, } from "./settings"; import { PreferencesSettingsTab } from "./PreferencesSettingsTab"; import { Slider } from "../Slider"; import { DeviceSelection } from "./DeviceSelection"; +import { useTrackProcessor } from "../livekit/TrackProcessorContext"; import { DeveloperSettingsTab } from "./DeveloperSettingsTab"; +import { FieldRow, InputField } from "../input/Input"; type SettingsTab = | "audio" @@ -60,6 +63,34 @@ export const SettingsModal: FC = ({ }) => { const { t } = useTranslation(); + // Generate a `Checkbox` input to turn blur on or off. + const BlurCheckbox: React.FC = (): ReactNode => { + const { supported, checkSupported } = useTrackProcessor() || {}; + useEffect(() => checkSupported?.(), [checkSupported]); + + const [blurActive, setBlurActive] = useSetting(backgroundBlurSetting); + + return ( + <> +

{t("settings.background_blur_header")}

+ + + setBlurActive(b.target.checked)} + disabled={!supported} + /> + + + ); + }; + const devices = useMediaDevices(); useMediaDeviceNames(devices, open); const [soundVolume, setSoundVolume] = useSetting(soundEffectVolumeSetting); @@ -107,13 +138,17 @@ export const SettingsModal: FC = ({ key: "video", name: t("common.video"), content: ( -
- t("settings.devices.camera_numbered", { n })} - /> - + <> +
+ t("settings.devices.camera_numbered", { n })} + /> + + + + ), }; diff --git a/src/settings/settings.ts b/src/settings/settings.ts index ebb5dffc4..679527ef9 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -91,6 +91,8 @@ export const videoInput = new Setting( undefined, ); +export const backgroundBlur = new Setting("background-blur", false); + export const showHandRaisedTimer = new Setting( "hand-raised-show-timer", false, diff --git a/yarn.lock b/yarn.lock index d3b8da400..0460f4bca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1941,9 +1941,9 @@ rxjs "7.8.1" "@livekit/components-react@^2.0.0": - version "2.6.9" - resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-2.6.9.tgz#2ff4691dc2cae6ed4c4b2e586a255d00e494bf9c" - integrity sha512-j43i/Dm8dlI2jxv5wv0s+69QPVqVEjg0y2tyznfs/7RDcaIZsIIzNijPu1kLditerzvzQdRsOgFQ3UWONcTkGA== + version "2.6.10" + resolved "https://registry.yarnpkg.com/@livekit/components-react/-/components-react-2.6.10.tgz#949d6e65e8507e2d8a4c75bf190adf56f6358175" + integrity sha512-aR8rqCIEvT3QYHuVEm67THRmNd9x25FTmU3Phi928FhzQJXDBO0N1/5d6qEE/wuDOgXMOoBgA98qsdYDIi2f+g== dependencies: "@livekit/components-core" "0.11.10" clsx "2.1.1" @@ -1961,16 +1961,39 @@ dependencies: "@bufbuild/protobuf" "^1.10.0" -"@matrix-org/matrix-sdk-crypto-wasm@^12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-12.0.0.tgz#e3a5150ccbb21d5e98ee3882e7057b9f17fb962a" - integrity sha512-nkkXAxUIk9UTso4TbU6Bgqsv/rJShXQXRx0ti/W+AWXHJ2HoH4sL5LsXkc7a8yYGn8tyXqxGPsYA1UeHqLwm0Q== +"@livekit/track-processors@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@livekit/track-processors/-/track-processors-0.3.2.tgz#eaff6a48b556c25e85f5dd2c4daf6dcf1bc3b143" + integrity sha512-4JUCzb7yIKoVsTo8J6FTzLZJHcI6DihfX/pGRDg0SOGaxprcDPrt8jaDBBTsnGBSXHeMxl2ugN+xQjdCWzLKEA== + dependencies: + "@mediapipe/holistic" "0.5.1675471629" + "@mediapipe/tasks-vision" "0.10.9" + +"@matrix-org/matrix-sdk-crypto-wasm@^11.0.0": + version "11.0.0" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-11.0.0.tgz#c49a1a0d1e367d3c00a2144a4ab23caee0b1eec2" + integrity sha512-a7NUH8Kjc8hwzNCPpkOGXoceFqWJiWvA8OskXeDrKyODJuDz4yKrZ/nvgaVRfQe45Ab5UC1ZXYqaME+ChlJuqg== "@matrix-org/olm@3.2.15": version "3.2.15" resolved "https://registry.yarnpkg.com/@matrix-org/olm/-/olm-3.2.15.tgz#55f3c1b70a21bbee3f9195cecd6846b1083451ec" integrity sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q== +"@mediapipe/holistic@0.5.1675471629": + version "0.5.1675471629" + resolved "https://registry.yarnpkg.com/@mediapipe/holistic/-/holistic-0.5.1675471629.tgz#f1127d43161ff27e8889d5d39aaea164f9730980" + integrity sha512-qY+cxtDeSOvVtevrLgnodiwXYaAtPi7dHZtNv/bUCGEjFicAOYtMmrZSqMmbPkTB2+4jLnPF1vgshkAqQRSYAw== + +"@mediapipe/tasks-vision@0.10.9": + version "0.10.9" + resolved "https://registry.yarnpkg.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.9.tgz#fbd669f50ac2e888b2c64c9c9863927c111da02f" + integrity sha512-/gFguyJm1ng4Qr7VVH2vKO+zZcQd8wc3YafUfvBuYFX0Y5+CvrV+VNPEVkl5W/gUZF5KNKNZAiaHPULGPCIjyQ== + +"@mediapipe/tasks-vision@^0.10.18": + version "0.10.18" + resolved "https://registry.yarnpkg.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.18.tgz#9ea0f0bf7506378c55ee661fa70aa0910f21f9b5" + integrity sha512-NRIlyqhGUz1Jdgcs6YybwPRhLK6dgeGAqAMXepIczEQ7FmA/0ouFtgMO1g9SPf/HaDSO8pNVdP54dAb9s9wj/Q== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -3277,6 +3300,18 @@ resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.8.tgz#319644d07ee6b4bfc734483008393b89b99f0219" integrity sha512-1tBhmVUeso3+ahfyaKluXe38p+94lovUZdoVfQ3OnJo9uJC42JT7CBoN3k9HYhAae+GwiBYmHu+N9FZhOG+2Pg== +"@types/dom-mediacapture-transform@^0.1.10": + version "0.1.10" + resolved "https://registry.yarnpkg.com/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.10.tgz#93e2c04284c95dd2faa2992216417599ee9d27a6" + integrity sha512-zUxMN2iShu7p3Fz5sqfvLp93qW/3sLs+RwXWWOkMb969hsuoVqUUokqrENjXqTMNmEEcVXKoHuMMbIGcWyrVVA== + dependencies: + "@types/dom-webcodecs" "*" + +"@types/dom-webcodecs@*": + version "0.1.13" + resolved "https://registry.yarnpkg.com/@types/dom-webcodecs/-/dom-webcodecs-0.1.13.tgz#d8be5da4f01b20721307b08ad2cca903ccf4f47f" + integrity sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ== + "@types/estree@1.0.6", "@types/estree@^1.0.0": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" @@ -6568,10 +6603,10 @@ matrix-events-sdk@0.0.1: matrix-js-sdk@matrix-org/matrix-js-sdk#develop: version "34.13.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/e4182eb75227c283a18704727021e99ced72868d" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/d1de32ea2773df4c6f8a956678bbd19b6d022475" dependencies: "@babel/runtime" "^7.12.5" - "@matrix-org/matrix-sdk-crypto-wasm" "^12.0.0" + "@matrix-org/matrix-sdk-crypto-wasm" "^11.0.0" "@matrix-org/olm" "3.2.15" another-json "^0.2.0" bs58 "^6.0.0"