ref(TS) Convert some components to TS (#13179)

pull/13187/head jitsi-meet_8528
Robert Pintilii 2 years ago committed by GitHub
parent fd47225d30
commit c1f1c0d341
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 64
      react/features/base/media/components/web/AudioTrack.tsx
  2. 92
      react/features/base/media/components/web/VideoTrack.tsx
  3. 2
      react/features/base/react/Platform.web.ts
  4. 2
      react/features/base/tracks/loadEffects.web.ts
  5. 2
      react/features/calendar-sync/actions.web.ts
  6. 2
      react/features/connection-indicator/components/web/ConnectionIndicator.tsx
  7. 38
      react/features/connection-indicator/components/web/ConnectionIndicatorIcon.tsx
  8. 2
      react/features/deep-linking/components/DeepLinkingMobilePage.web.tsx
  9. 17
      react/features/deep-linking/functions.ts
  10. 6
      react/features/deep-linking/openDesktopApp.ts
  11. 2
      react/features/filmstrip/components/web/AudioTracksContainer.tsx
  12. 2
      react/features/filmstrip/components/web/Thumbnail.tsx
  13. 1
      react/features/filmstrip/components/web/VirtualScreenshareParticipant.tsx
  14. 37
      react/features/google-api/actions.ts
  15. 71
      react/features/invite/components/dial-in-summary/web/DialInSummary.tsx
  16. 4
      react/features/invite/components/dial-in-summary/web/NumbersList.tsx
  17. 3
      react/features/prejoin/components/web/Prejoin.tsx
  18. 5
      react/features/prejoin/components/web/dialogs/CallingDialog.tsx
  19. 6
      react/features/prejoin/components/web/dialogs/DialInDialog.tsx
  20. 55
      react/features/prejoin/components/web/dialogs/JoinByPhoneDialog.tsx
  21. 2
      react/features/recent-list/components/AbstractRecentList.tsx
  22. 4
      react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx
  23. 2
      react/features/remote-control/actions.ts
  24. 31
      react/features/remote-control/components/RemoteControlAuthorizationDialog.tsx
  25. 66
      react/features/stream-effects/virtual-background/JitsiStreamBackgroundEffect.ts
  26. 1
      react/features/stream-effects/virtual-background/TimerWorker.ts
  27. 22
      react/features/stream-effects/virtual-background/index.ts
  28. 2
      react/features/virtual-background/actions.ts
  29. 2
      react/features/virtual-background/reducer.ts
  30. 1
      tsconfig.native.json

@ -1,63 +1,62 @@
// @flow
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createAudioPlayErrorEvent, createAudioPlaySuccessEvent } from '../../../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../../../analytics/functions';
import { IReduxState } from '../../../../app/types';
import { ITrack } from '../../../tracks/types';
import logger from '../../logger';
/**
* The type of the React {@code Component} props of {@link AudioTrack}.
*/
type Props = {
interface IProps {
/**
* Represents muted property of the underlying audio element.
*/
_muted: ?Boolean,
_muted?: boolean;
/**
* Represents volume property of the underlying audio element.
*/
_volume: ?number,
/**
* The value of the id attribute of the audio element.
*/
id: string,
_volume?: number | boolean;
/**
* The audio track.
*/
audioTrack: ?Object,
audioTrack?: ITrack;
/**
* Used to determine the value of the autoplay attribute of the underlying
* audio element.
*/
autoPlay: boolean,
autoPlay: boolean;
/**
* The value of the id attribute of the audio element.
*/
id: string;
/**
* The ID of the participant associated with the audio element.
*/
participantId: string
};
participantId: string;
}
/**
* The React/Web {@link Component} which is similar to and wraps around {@code HTMLAudioElement}.
*/
class AudioTrack extends Component<Props> {
class AudioTrack extends Component<IProps> {
/**
* Reference to the HTML audio element, stored until the file is ready.
*/
_ref: ?HTMLAudioElement;
_ref: HTMLAudioElement | null;
/**
* The current timeout ID for play() retries.
*/
_playTimeout: ?TimeoutID;
_playTimeout: number | undefined;
/**
* Default values for {@code AudioTrack} component's properties.
@ -76,7 +75,7 @@ class AudioTrack extends Component<Props> {
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once for every instance.
@ -106,6 +105,7 @@ class AudioTrack extends Component<Props> {
this._ref.muted = _muted;
}
// @ts-ignore
this._ref.addEventListener('error', this._errorHandler);
}
}
@ -119,7 +119,9 @@ class AudioTrack extends Component<Props> {
*/
componentWillUnmount() {
this._detachTrack(this.props.audioTrack);
this._ref.removeEventListener('error', this._errorHandler);
// @ts-ignore
this._ref?.removeEventListener('error', this._errorHandler);
}
/**
@ -130,7 +132,7 @@ class AudioTrack extends Component<Props> {
* @returns {boolean} - False is always returned to blackbox this component
* from React.
*/
shouldComponentUpdate(nextProps: Props) {
shouldComponentUpdate(nextProps: IProps) {
const currentJitsiTrack = this.props.audioTrack?.jitsiTrack;
const nextJitsiTrack = nextProps.audioTrack?.jitsiTrack;
@ -182,7 +184,7 @@ class AudioTrack extends Component<Props> {
* @private
* @returns {void}
*/
_attachTrack(track) {
_attachTrack(track?: ITrack) {
if (!track || !track.jitsiTrack) {
return;
}
@ -199,7 +201,7 @@ class AudioTrack extends Component<Props> {
* @private
* @returns {void}
*/
_detachTrack(track) {
_detachTrack(track?: ITrack) {
if (this._ref && track && track.jitsiTrack) {
clearTimeout(this._playTimeout);
this._playTimeout = undefined;
@ -207,23 +209,19 @@ class AudioTrack extends Component<Props> {
}
}
_errorHandler: (?Error) => void;
/**
* Reattaches the audio track to the underlying HTMLAudioElement when an 'error' event is fired.
*
* @param {Error} error - The error event fired on the HTMLAudioElement.
* @returns {void}
*/
_errorHandler(error) {
_errorHandler(error: Error) {
logger.error(`Error ${error?.message} called on audio track ${this.props.audioTrack?.jitsiTrack}. `
+ 'Attempting to reattach the audio track to the element and execute play on it');
this._detachTrack(this.props.audioTrack);
this._attachTrack(this.props.audioTrack);
}
_play: ?number => void;
/**
* Plays the underlying HTMLAudioElement.
*
@ -254,7 +252,7 @@ class AudioTrack extends Component<Props> {
logger.error(`Failed to play audio track! retry: ${retries} ; Error: ${e}`);
if (retries < 3) {
this._playTimeout = setTimeout(() => this._play(retries + 1), 1000);
this._playTimeout = window.setTimeout(() => this._play(retries + 1), 1000);
if (retries === 0) {
// send only 1 error event.
@ -267,8 +265,6 @@ class AudioTrack extends Component<Props> {
}
}
_setRef: (?HTMLAudioElement) => void;
/**
* Sets the reference to the HTML audio element.
*
@ -276,7 +272,7 @@ class AudioTrack extends Component<Props> {
* @private
* @returns {void}
*/
_setRef(audioElement: ?HTMLAudioElement) {
_setRef(audioElement: HTMLAudioElement | null) {
this._ref = audioElement;
}
}
@ -287,9 +283,9 @@ class AudioTrack extends Component<Props> {
* @param {Object} state - The Redux state.
* @param {Object} ownProps - The props passed to the component.
* @private
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: any) {
const { participantsVolume } = state['features/filmstrip'];
return {

@ -1,132 +1,130 @@
/* @flow */
import React from 'react';
import React, { ReactEventHandler } from 'react';
import { connect } from 'react-redux';
import AbstractVideoTrack from '../AbstractVideoTrack';
import type { Props as AbstractVideoTrackProps } from '../AbstractVideoTrack';
import { IReduxState } from '../../../../app/types';
import AbstractVideoTrack, { IProps as AbstractVideoTrackProps } from '../AbstractVideoTrack';
import Video from './Video';
/**
* The type of the React {@code Component} props of {@link VideoTrack}.
*/
type Props = AbstractVideoTrackProps & {
/**
* CSS classes to add to the video element.
*/
className: string,
/**
* The value of the id attribute of the video. Used by the torture tests
* to locate video elements.
*/
id: string,
interface IProps extends AbstractVideoTrackProps {
/**
*
* Used to determine the value of the autoplay attribute of the underlying
* video element.
*/
_noAutoPlayVideo: boolean,
_noAutoPlayVideo: boolean;
/**
* CSS classes to add to the video element.
*/
className: string;
/**
* A map of the event handlers for the video HTML element.
*/
eventHandlers?: {|
eventHandlers?: {
/**
* OnAbort event handler.
*/
onAbort?: ?Function,
onAbort?: ReactEventHandler<HTMLVideoElement>;
/**
* OnCanPlay event handler.
*/
onCanPlay?: ?Function,
onCanPlay?: ReactEventHandler<HTMLVideoElement>;
/**
* OnCanPlayThrough event handler.
*/
onCanPlayThrough?: ?Function,
onCanPlayThrough?: ReactEventHandler<HTMLVideoElement>;
/**
* OnEmptied event handler.
*/
onEmptied?: ?Function,
onEmptied?: ReactEventHandler<HTMLVideoElement>;
/**
* OnEnded event handler.
*/
onEnded?: ?Function,
onEnded?: ReactEventHandler<HTMLVideoElement>;
/**
* OnError event handler.
*/
onError?: ?Function,
onError?: ReactEventHandler<HTMLVideoElement>;
/**
* OnLoadedData event handler.
* OnLoadStart event handler.
*/
onLoadedData?: ?Function,
onLoadStart?: ReactEventHandler<HTMLVideoElement>;
/**
* OnLoadedMetadata event handler.
* OnLoadedData event handler.
*/
onLoadedMetadata?: ?Function,
onLoadedData?: ReactEventHandler<HTMLVideoElement>;
/**
* OnLoadStart event handler.
* OnLoadedMetadata event handler.
*/
onLoadStart?: ?Function,
onLoadedMetadata?: ReactEventHandler<HTMLVideoElement>;
/**
* OnPause event handler.
*/
onPause?: ?Function,
onPause?: ReactEventHandler<HTMLVideoElement>;
/**
* OnPlay event handler.
*/
onPlay?: ?Function,
onPlay?: ReactEventHandler<HTMLVideoElement>;
/**
* OnPlaying event handler.
*/
onPlaying?: ?Function,
onPlaying?: ReactEventHandler<HTMLVideoElement>;
/**
* OnRateChange event handler.
*/
onRateChange?: ?Function,
onRateChange?: ReactEventHandler<HTMLVideoElement>;
/**
* OnStalled event handler.
*/
onStalled?: ?Function,
onStalled?: ReactEventHandler<HTMLVideoElement>;
/**
* OnSuspend event handler.
*/
onSuspend?: ?Function,
onSuspend?: ReactEventHandler<HTMLVideoElement>;
/**
* OnWaiting event handler.
*/
onWaiting?: ?Function,
|},
onWaiting?: ReactEventHandler<HTMLVideoElement>;
};
/**
* A styles that will be applied on the video element.
* The value of the id attribute of the video. Used by the torture tests
* to locate video elements.
*/
style: Object,
id: string;
/**
* The value of the muted attribute for the underlying element.
*/
muted?: boolean
};
muted?: boolean;
/**
* A styles that will be applied on the video element.
*/
style: Object;
}
/**
* Component that renders a video element for a passed in video track and
@ -134,7 +132,7 @@ type Props = AbstractVideoTrackProps & {
*
* @augments AbstractVideoTrack
*/
class VideoTrack extends AbstractVideoTrack<Props> {
class VideoTrack extends AbstractVideoTrack<IProps> {
/**
* Default values for {@code VideoTrack} component's properties.
*
@ -176,8 +174,6 @@ class VideoTrack extends AbstractVideoTrack<Props> {
videoTrack = { videoTrack } />
);
}
_onVideoPlaying: () => void;
}
@ -190,11 +186,11 @@ class VideoTrack extends AbstractVideoTrack<Props> {
* _noAutoPlayVideo: boolean
* }}
*/
function _mapStateToProps(state) {
function _mapStateToProps(state: IReduxState) {
const testingConfig = state['features/base/config'].testing;
return {
_noAutoPlayVideo: testingConfig?.noAutoPlayVideo
_noAutoPlayVideo: Boolean(testingConfig?.noAutoPlayVideo)
};
}

@ -1,6 +1,6 @@
// @ts-ignore
const { userAgent, maxTouchPoints, platform } = navigator;
let OS;
let OS = '';
if (userAgent.match(/Android/i)) {
OS = 'android';

@ -1,6 +1,4 @@
import { IStore } from '../../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { createVirtualBackgroundEffect } from '../../stream-effects/virtual-background';
import logger from './logger';

@ -4,8 +4,6 @@ import { generateRoomWithoutSeparator } from '@jitsi/js-utils/random';
import { createCalendarConnectedEvent } from '../analytics/AnalyticsEvents';
import { sendAnalytics } from '../analytics/functions';
import { IStore } from '../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { loadGoogleAPI } from '../google-api/actions';
import {

@ -31,8 +31,6 @@ import AbstractConnectionIndicator, {
} from '../AbstractConnectionIndicator';
import ConnectionIndicatorContent from './ConnectionIndicatorContent';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { ConnectionIndicatorIcon } from './ConnectionIndicatorIcon';
/**

@ -1,47 +1,50 @@
// @flow
import clsx from 'clsx';
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import Icon from '../../../base/icons/components/Icon';
import { IconConnection, IconConnectionInactive } from '../../../base/icons/svg';
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
import { trackStreamingStatusChanged } from '../../../base/tracks/actions.web';
import { ITrack } from '../../../base/tracks/types';
type Props = {
interface IProps {
/**
* An object containing the CSS classes.
*/
classes: Object,
classes: any;
/**
* A CSS class that interprets the current connection status as a color.
*/
colorClass: string,
colorClass: string;
/**
* Disable/enable inactive indicator.
*/
connectionIndicatorInactiveDisabled: boolean,
connectionIndicatorInactiveDisabled: boolean;
/**
* JitsiTrack instance.
* Whether or not the connection status is inactive.
*/
track: Object,
isConnectionStatusInactive: boolean;
/**
* Whether or not the connection status is inactive.
* Whether or not the connection status is interrupted.
*/
isConnectionStatusInactive: boolean,
isConnectionStatusInterrupted?: boolean;
/**
* Whether or not the connection status is interrupted.
* JitsiTrack instance.
*/
isConnectionStatusInterrupted: boolean,
track?: ITrack;
}
const useStyles = makeStyles()(() => {
return {};
});
export const ConnectionIndicatorIcon = ({
classes,
colorClass,
@ -49,11 +52,12 @@ export const ConnectionIndicatorIcon = ({
isConnectionStatusInactive,
isConnectionStatusInterrupted,
track
}: Props) => {
}: IProps) => {
const { cx } = useStyles();
const dispatch = useDispatch();
const sourceName = track?.jitsiTrack?.getSourceName();
const handleTrackStreamingStatusChanged = (jitsiTrack, streamingStatus) => {
const handleTrackStreamingStatusChanged = (jitsiTrack: any, streamingStatus: string) => {
dispatch(trackStreamingStatusChanged(jitsiTrack, streamingStatus));
};
@ -86,7 +90,7 @@ export const ConnectionIndicatorIcon = ({
return (
<span className = 'connection_ninja'>
<Icon
className = { clsx(classes.icon, classes.inactiveIcon, colorClass) }
className = { cx(classes.icon, classes.inactiveIcon, colorClass) }
size = { 24 }
src = { IconConnectionInactive } />
</span>
@ -103,7 +107,7 @@ export const ConnectionIndicatorIcon = ({
return (
<span className = { emptyIconWrapperClassName }>
<Icon
className = { clsx(classes.icon, colorClass) }
className = { cx(classes.icon, colorClass) }
size = { 16 }
src = { IconConnection } />
</span>

@ -14,11 +14,9 @@ import { translate } from '../../base/i18n/functions';
import Platform from '../../base/react/Platform.web';
import { withPixelLineHeight } from '../../base/styles/functions.web';
import Button from '../../base/ui/components/web/Button';
// @ts-ignore
import DialInSummary from '../../invite/components/dial-in-summary/web/DialInSummary';
import { openWebApp } from '../actions';
import { _TNS } from '../constants';
// @ts-ignore
import { generateDeepLinkingURL } from '../functions';

@ -1,14 +1,18 @@
/* global interfaceConfig */
/* eslint-disable lines-around-comment */
import { IReduxState } from '../app/types';
import { isMobileBrowser } from '../base/environment/utils';
import Platform from '../base/react/Platform';
import { URI_PROTOCOL_PATTERN } from '../base/util/uri';
import { isVpaasMeeting } from '../jaas/functions';
// @ts-ignore
import DeepLinkingDesktopPage from './components/DeepLinkingDesktopPage';
// @ts-ignore
import DeepLinkingMobilePage from './components/DeepLinkingMobilePage';
// @ts-ignore
import NoMobileApp from './components/NoMobileApp';
import { _openDesktopApp } from './openDesktopApp';
/* eslint-enable lines-around-comment */
/**
* Generates a deep linking URL based on the current window URL.
@ -17,7 +21,7 @@ import { _openDesktopApp } from './openDesktopApp';
*
* @returns {string} - The generated URL.
*/
export function generateDeepLinkingURL(state) {
export function generateDeepLinkingURL(state: IReduxState) {
// If the user installed the app while this Component was displayed
// (e.g. the user clicked the Download the App button), then we would
// like to open the current URL in the mobile app. The only way to do it
@ -27,6 +31,7 @@ export function generateDeepLinkingURL(state) {
const { href } = window.location;
const regex = new RegExp(URI_PROTOCOL_PATTERN, 'gi');
// @ts-ignore
const mobileConfig = state['features/base/config'].deeplinking?.[Platform.OS] || {};
const { appScheme, appPackage } = mobileConfig;
@ -51,11 +56,11 @@ export function generateDeepLinkingURL(state) {
* @param {Object} state - Object containing current redux state.
* @returns {Promise<Component>}
*/
export function getDeepLinkingPage(state) {
export function getDeepLinkingPage(state: IReduxState) {
const { room } = state['features/base/conference'];
const { launchInWeb } = state['features/deep-linking'];
const deeplinking = state['features/base/config'].deeplinking || {};
const { appScheme } = deeplinking?.[Platform.OS] || {};
const { appScheme } = deeplinking?.[Platform.OS as keyof typeof deeplinking] || {};
// Show only if we are about to join a conference.
if (launchInWeb
@ -87,6 +92,6 @@ export function getDeepLinkingPage(state) {
* @returns {Promise<boolean>} - Resolves with true if the attempt to open the desktop app was successful and resolves
* with false otherwise.
*/
export function openDesktopApp(state) {
export function openDesktopApp(state: IReduxState) {
return _openDesktopApp(state);
}

@ -1,12 +1,10 @@
// @flow
/**
* Opens the desktop app.
*
* @param {Object} state - Object containing current redux state.
* @param {Object} _state - Object containing current redux state.
* @returns {Promise<boolean>} - Resolves with true if the attempt to open the desktop app was successful and resolves
* with false otherwise.
*/
export function _openDesktopApp(state: Object) { // eslint-disable-line no-unused-vars
export function _openDesktopApp(_state: Object) {
return Promise.resolve(false);
}

@ -2,8 +2,6 @@ import React from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import AudioTrack from '../../../base/media/components/web/AudioTrack';
import { MEDIA_TYPE } from '../../../base/media/constants';
import { ITrack } from '../../../base/tracks/types';

@ -13,8 +13,6 @@ import Avatar from '../../../base/avatar/components/Avatar';
import { isMobileBrowser } from '../../../base/environment/utils';
import { translate } from '../../../base/i18n/functions';
import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import VideoTrack from '../../../base/media/components/web/VideoTrack';
import { MEDIA_TYPE } from '../../../base/media/constants';
import { pinParticipant } from '../../../base/participants/actions';

@ -2,7 +2,6 @@ import clsx from 'clsx';
import React, { TouchEventHandler } from 'react';
import { useSelector } from 'react-redux';
// @ts-ignore
import VideoTrack from '../../../base/media/components/web/VideoTrack';
import { ITrack } from '../../../base/tracks/types';
import { LAYOUTS } from '../../../video-layout/constants';

@ -1,7 +1,4 @@
// @flow
import type { Dispatch } from 'redux';
import { IStore } from '../app/types';
import { getShareInfoText } from '../invite/functions';
import { getLiveStreaming } from '../recording/components/LiveStream/functions';
@ -10,7 +7,9 @@ import {
SET_GOOGLE_API_STATE
} from './actionTypes';
import { GOOGLE_API_STATES } from './constants';
import googleApi from './googleApi';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import googleApi from './googleApi.web';
/**
* Retrieves the current calendar events.
@ -20,7 +19,7 @@ import googleApi from './googleApi';
* @returns {function(Dispatch<any>): Promise<CalendarEntries>}
*/
export function getCalendarEntries(
fetchStartDays: ?number, fetchEndDays: ?number) {
fetchStartDays?: number, fetchEndDays?: number) {
return () =>
googleApi.get()
.then(() =>
@ -33,7 +32,7 @@ export function getCalendarEntries(
* @returns {Function}
*/
export function loadGoogleAPI() {
return (dispatch: Dispatch<any>, getState: Function) =>
return (dispatch: IStore['dispatch'], getState: IStore['getState']) =>
googleApi.get()
.then(() => {
const {
@ -54,7 +53,7 @@ export function loadGoogleAPI() {
.then(() => dispatch(setGoogleAPIState(GOOGLE_API_STATES.LOADED)))
.then(() => googleApi.signInIfNotSignedIn())
.then(() => googleApi.isSignedIn())
.then(isSignedIn => {
.then((isSignedIn: boolean) => {
if (isSignedIn) {
dispatch(setGoogleAPIState(GOOGLE_API_STATES.SIGNED_IN));
}
@ -70,13 +69,13 @@ export function loadGoogleAPI() {
export function requestAvailableYouTubeBroadcasts() {
return () =>
googleApi.requestAvailableYouTubeBroadcasts()
.then(response => {
.then((response: any) => {
// Takes in a list of broadcasts from the YouTube API,
// removes dupes, removes broadcasts that cannot get a stream key,
// and parses the broadcasts into flat objects.
const broadcasts = response.result.items;
const parsedBroadcasts = {};
const parsedBroadcasts: any = {};
for (let i = 0; i < broadcasts.length; i++) {
const broadcast = broadcasts[i];
@ -109,11 +108,9 @@ export function requestAvailableYouTubeBroadcasts() {
export function requestLiveStreamsForYouTubeBroadcast(boundStreamID: string) {
return () =>
googleApi.requestLiveStreamsForYouTubeBroadcast(boundStreamID)
.then(response => {
.then((response: any) => {
const broadcasts = response.result.items;
const streamName = broadcasts
&& broadcasts[0]
&& broadcasts[0].cdn.ingestionInfo.streamName;
const streamName = broadcasts?.[0]?.cdn.ingestionInfo.streamName;
const streamKey = streamName || '';
return {
@ -134,7 +131,7 @@ export function requestLiveStreamsForYouTubeBroadcast(boundStreamID: string) {
* }}
*/
export function setGoogleAPIState(
googleAPIState: number, googleResponse: ?Object) {
googleAPIState: number, googleResponse?: Object) {
return {
type: SET_GOOGLE_API_STATE,
googleAPIState,
@ -160,7 +157,7 @@ export function showAccountSelection() {
* @returns {function(Dispatch<any>): Promise<string | never>}
*/
export function signIn() {
return (dispatch: Dispatch<any>) => googleApi.get()
return (dispatch: IStore['dispatch']) => googleApi.get()
.then(() => googleApi.signInIfNotSignedIn(true))
.then(() => dispatch({
type: SET_GOOGLE_API_STATE,
@ -174,7 +171,7 @@ export function signIn() {
* @returns {function(Dispatch<any>): Promise<string | never>}
*/
export function signOut() {
return (dispatch: Dispatch<any>) =>
return (dispatch: IStore['dispatch']) =>
googleApi.get()
.then(() => googleApi.signOut())
.then(() => {
@ -195,14 +192,14 @@ export function signOut() {
* @returns {function(Dispatch<any>): Promise<string | never>}
*/
export function updateProfile() {
return (dispatch: Dispatch<any>) => googleApi.get()
return (dispatch: IStore['dispatch']) => googleApi.get()
.then(() => googleApi.signInIfNotSignedIn())
.then(() => dispatch({
type: SET_GOOGLE_API_STATE,
googleAPIState: GOOGLE_API_STATES.SIGNED_IN
}))
.then(() => googleApi.getCurrentUserProfile())
.then(profile => {
.then((profile: any) => {
dispatch({
type: SET_GOOGLE_API_PROFILE,
profileEmail: profile.email
@ -222,7 +219,7 @@ export function updateProfile() {
*/
export function updateCalendarEvent(
id: string, calendarId: string, location: string) {
return (dispatch: Dispatch<any>, getState: Function) =>
return (dispatch: IStore['dispatch'], getState: IStore['getState']) =>
getShareInfoText(getState(), location)
.then(text =>
googleApi._updateCalendarEntry(id, calendarId, location, text));

@ -1,10 +1,8 @@
// @flow
import { Theme } from '@mui/material';
import { withStyles } from '@mui/styles';
import clsx from 'clsx';
import React, { Component } from 'react';
import { WithTranslation } from 'react-i18next';
import { translate } from '../../../../base/i18n/functions';
import { withPixelLineHeight } from '../../../../base/styles/functions.web';
@ -13,17 +11,15 @@ import { getDialInConferenceID, getDialInNumbers } from '../../../_utils';
import ConferenceID from './ConferenceID';
import NumbersList from './NumbersList';
declare var config: Object;
/**
* The type of the React {@code Component} props of {@link DialInSummary}.
*/
type Props = {
interface IProps extends WithTranslation {
/**
* Additional CSS classnames to append to the root of the component.
*/
className: string,
className: string;
/**
* An object containing the CSS classes.
@ -33,33 +29,28 @@ type Props = {
/**
* Whether or not numbers should include links with the telephone protocol.
*/
clickableNumbers: boolean,
clickableNumbers: boolean;
/**
* The name of the conference to show a conferenceID for.
*/
room: string,
room: string;
/**
* Whether the dial in summary container is scrollable.
*/
scrollable: Boolean,
scrollable?: boolean;
/**
* Whether the room name should show as title.
*/
showTitle?: boolean,
showTitle?: boolean;
/**
* The url where we were loaded.
*/
url: URL | string,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
url: any;
}
/**
* The type of the React {@code Component} state of {@link DialInSummary}.
@ -69,41 +60,41 @@ type State = {
/**
* The numeric ID of the conference, used as a pin when dialing in.
*/
conferenceID: ?string,
conferenceID: string | null;
/**
* An error message to display.
*/
error: string,
error: string;
/**
* Whether or not the app is fetching data.
*/
loading: boolean,
loading: boolean;
/**
* The dial-in numbers to be displayed.
*/
numbers: ?Array<Object> | ?Object,
numbers: Array<Object> | Object | null;
/**
* Whether or not dial-in is allowed.
*/
numbersEnabled: ?boolean
}
numbersEnabled: boolean | null;
};
const styles = (theme: Theme) => {
return {
hasNumbers: {
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
flexDirection: 'column' as const,
background: '#1E1E1E',
color: theme.palette.text01
},
scrollable: {
height: '100vh',
overflowY: 'scroll'
overflowY: 'scroll' as const
},
roomName: {
margin: '40px auto 8px',
@ -118,7 +109,7 @@ const styles = (theme: Theme) => {
*
* @augments Component
*/
class DialInSummary extends Component<Props, State> {
class DialInSummary extends Component<IProps, State> {
state = {
conferenceID: null,
error: '',
@ -133,7 +124,7 @@ class DialInSummary extends Component<Props, State> {
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once for every instance.
@ -219,7 +210,7 @@ class DialInSummary extends Component<Props, State> {
_getConferenceID() {
const { room } = this.props;
const { dialInConfCodeUrl, hosts } = config;
const mucURL = hosts && hosts.muc;
const mucURL = hosts?.muc;
if (!dialInConfCodeUrl || !mucURL || !room) {
return Promise.resolve();
@ -229,6 +220,7 @@ class DialInSummary extends Component<Props, State> {
let url = this.props.url || {};
if (typeof url === 'string' || url instanceof String) {
// @ts-ignore
url = new URL(url);
}
@ -245,18 +237,16 @@ class DialInSummary extends Component<Props, State> {
_getNumbers() {
const { room } = this.props;
const { dialInNumbersUrl, hosts } = config;
const mucURL = hosts && hosts.muc;
const mucURL = hosts?.muc;
if (!dialInNumbersUrl) {
return Promise.reject(this.props.t('info.dialInNotSupported'));
}
return getDialInNumbers(dialInNumbersUrl, room, mucURL)
return getDialInNumbers(dialInNumbersUrl, room, mucURL ?? '')
.catch(() => Promise.reject(this.props.t('info.genericError')));
}
_onGetConferenceIDSuccess: (Object) => void;
/**
* Callback invoked when fetching the conference ID succeeds.
*
@ -264,7 +254,8 @@ class DialInSummary extends Component<Props, State> {
* @private
* @returns {void}
*/
_onGetConferenceIDSuccess(response = {}) {
_onGetConferenceIDSuccess(response = { conference: undefined,
id: undefined }) {
const { conference, id } = response;
if (!conference || !id) {
@ -274,8 +265,6 @@ class DialInSummary extends Component<Props, State> {
this.setState({ conferenceID: id });
}
_onGetNumbersSuccess: (Object) => void;
/**
* Callback invoked when fetching dial-in numbers succeeds. Sets the
* internal to show the numbers.
@ -289,18 +278,16 @@ class DialInSummary extends Component<Props, State> {
* @returns {void}
*/
_onGetNumbersSuccess(
response: Array<Object> | { numbersEnabled?: boolean }) {
response: Array<Object> | { numbersEnabled?: boolean; }) {
this.setState({
numbersEnabled:
Array.isArray(response)
? response.length > 0 : response.numbersEnabled,
Boolean(Array.isArray(response)
? response.length > 0 : response.numbersEnabled),
numbers: response
});
}
_setErrorMessage: (string) => void;
/**
* Sets an error message to display on the page instead of content.
*
@ -308,7 +295,7 @@ class DialInSummary extends Component<Props, State> {
* @private
* @returns {void}
*/
_setErrorMessage(error) {
_setErrorMessage(error: string) {
this.setState({
error
});

@ -41,13 +41,13 @@ interface IProps extends WithTranslation {
/**
* The conference ID for dialing in.
*/
conferenceID: number;
conferenceID: number | null;
/**
* The phone numbers to display. Can be an array of number Objects or an
* object with countries as keys and an array of numbers as values.
*/
numbers: INumbersMapping;
numbers: INumbersMapping | null;
}

@ -31,7 +31,6 @@ import {
isPrejoinDisplayNameVisible
} from '../../functions';
// @ts-ignore
import JoinByPhoneDialog from './dialogs/JoinByPhoneDialog';
interface IProps extends WithTranslation {
@ -407,7 +406,7 @@ class Prejoin extends Component<IProps, IState> {
</div>
</div>
{ showDialog && (
<JoinByPhoneDialog
<JoinByPhoneDialog // @ts-ignore
joinConferenceWithoutAudio = { joinConferenceWithoutAudio }
onClose = { _closeDialog } />
)}

@ -20,11 +20,6 @@ interface IProps extends WithTranslation {
*/
onClose: Function;
/**
* Handler used on hangup click.
*/
onHangup: Function;
/**
* The status of the call.
*/

@ -14,7 +14,7 @@ interface IProps extends WithTranslation {
/**
* The number to call in order to join the conference.
*/
number: string;
number: string | null;
/**
* Handler used when clicking the back button.
@ -39,7 +39,7 @@ interface IProps extends WithTranslation {
/**
* The passCode of the conference.
*/
passCode: string;
passCode?: string | number;
}
const useStyles = makeStyles()(theme => {
@ -108,7 +108,7 @@ function DialinDialog(props: IProps) {
} = props;
const { classes } = useStyles();
const flagClassName = `prejoin-dialog-flag iti-flag ${getCountryCodeFromPhone(
number
number ?? ''
)}`;
return (

@ -1,98 +1,97 @@
// @flow
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../../app/types';
import { updateDialInNumbers } from '../../../../invite/actions.web';
import { getConferenceId, getDefaultDialInNumber } from '../../../../invite/functions';
import {
dialOut as dialOutAction,
joinConferenceWithoutAudio as joinConferenceWithoutAudioAction,
openDialInPage as openDialInPageAction
} from '../../../actions';
} from '../../../actions.web';
import { getDialOutStatus, getFullDialOutNumber } from '../../../functions';
import CallingDialog from './CallingDialog';
import DialInDialog from './DialInDialog';
import DialOutDialog from './DialOutDialog';
type Props = {
interface IProps {
/**
* The number to call in order to join the conference.
*/
dialInNumber: string,
dialInNumber: string | null;
/**
* The status of the call when the meeting calls the user.
* The action by which the meeting calls the user.
*/
dialOutStatus: string,
dialOut: Function;
/**
* The action by which the meeting calls the user.
* The number the conference should call.
*/
dialOut: Function,
dialOutNumber: string;
/**
* The number the conference should call.
* The status of the call when the meeting calls the user.
*/
dialOutNumber: string,
dialOutStatus: string;
/**
* Fetches conference dial in numbers & conference id.
*/
fetchConferenceDetails: Function,
fetchConferenceDetails: Function;
/**
* Joins the conference without audio.
*/
joinConferenceWithoutAudio: Function,
joinConferenceWithoutAudio: Function;
/**
* Closes the dialog.
*/
onClose: Function,
onClose: (e?: React.MouseEvent) => void;
/**
* Opens a web page with all the dial in numbers.
*/
openDialInPage: Function,
openDialInPage: (e?: React.MouseEvent) => void;
/**
* The passCode of the conference used when joining a meeting by phone.
*/
passCode: string,
};
passCode?: string | number;
}
type State = {
/**
* The dialout call is ongoing, 'CallingDialog' is shown;.
*/
isCalling: boolean,
isCalling: boolean;
/**
* If should show 'DialInDialog'.
*/
showDialIn: boolean,
showDialIn: boolean;
/**
* If should show 'DialOutDialog'.
*/
showDialOut: boolean
}
showDialOut: boolean;
};
/**
* This is the dialog shown when a user wants to join with phone audio.
*/
class JoinByPhoneDialog extends PureComponent<Props, State> {
class JoinByPhoneDialog extends PureComponent<IProps, State> {
/**
* Initializes a new {@code JoinByPhoneDialog} instance.
*
* @param {Props} props - The props of the component.
* @param {IProps} props - The props of the component.
* @inheritdoc
*/
constructor(props) {
constructor(props: IProps) {
super(props);
this.state = {
@ -106,8 +105,6 @@ class JoinByPhoneDialog extends PureComponent<Props, State> {
this._showDialOutDialog = this._showDialOutDialog.bind(this);
}
_dialOut: () => void;
/**
* Meeting calls the user & shows the 'CallingDialog'.
*
@ -124,8 +121,6 @@ class JoinByPhoneDialog extends PureComponent<Props, State> {
dialOut(joinConferenceWithoutAudio, this._showDialOutDialog);
}
_showDialInDialog: () => void;
/**
* Shows the 'DialInDialog'.
*
@ -139,8 +134,6 @@ class JoinByPhoneDialog extends PureComponent<Props, State> {
});
}
_showDialOutDialog: () => void;
/**
* Shows the 'DialOutDialog'.
*
@ -225,7 +218,7 @@ class JoinByPhoneDialog extends PureComponent<Props, State> {
* @param {Object} state - The redux state.
* @returns {Object}
*/
function mapStateToProps(state) {
function mapStateToProps(state: IReduxState) {
return {
dialInNumber: getDefaultDialInNumber(state),
dialOutNumber: getFullDialOutNumber(state),

@ -8,7 +8,7 @@ import AbstractPage from '../../base/react/components/AbstractPage';
import { Container, Text } from '../../base/react/components/index';
// @ts-ignore
import styles from './styles';
import styles from './styles.web';
/**
* The type of the React {@code Component} props of {@link AbstractRecentList}.

@ -12,11 +12,7 @@ import {
showAccountSelection,
signIn,
updateProfile
// @ts-ignore
} from '../../../../google-api/actions';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import GoogleSignInButton from '../../../../google-api/components/GoogleSignInButton.web';
import { GOOGLE_API_STATES } from '../../../../google-api/constants';
import AbstractStartLiveStreamDialog, {

@ -26,8 +26,6 @@ import {
SET_RECEIVER_TRANSPORT,
SET_REQUESTED_PARTICIPANT
} from './actionTypes';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import RemoteControlAuthorizationDialog from './components/RemoteControlAuthorizationDialog';
import {
DISCO_REMOTE_CONTROL_FEATURE,

@ -1,59 +1,56 @@
// @flow
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../app/types';
import { translate } from '../../base/i18n/functions';
import { getParticipantById } from '../../base/participants/functions';
import { getLocalVideoTrack } from '../../base/tracks/functions.any';
import Dialog from '../../base/ui/components/web/Dialog';
import { deny, grant } from '../actions';
declare var APP: Object;
/**
* The type of the React {@code Component} props of
* {@link RemoteControlAuthorizationDialog}.
*/
type Props = {
interface IProps {
/**
* The display name of the participant who is requesting authorization for
* remote desktop control session.
*/
_displayName: string,
_displayName: string;
_isScreenSharing: boolean,
_sourceType: string,
_isScreenSharing: boolean;
_sourceType: string;
/**
* Used to show/hide the dialog on cancel.
*/
dispatch: Function,
dispatch: Function;
/**
* The ID of the participant who is requesting authorization for remote
* desktop control session.
*/
participantId: string,
participantId: string;
/**
* Invoked to obtain translated strings.
*/
t: Function
};
t: Function;
}
/**
* Implements a dialog for remote control authorization.
*/
class RemoteControlAuthorizationDialog extends Component<Props> {
class RemoteControlAuthorizationDialog extends Component<IProps> {
/**
* Initializes a new RemoteControlAuthorizationDialog instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this._onCancel = this._onCancel.bind(this);
@ -105,8 +102,6 @@ class RemoteControlAuthorizationDialog extends Component<Props> {
);
}
_onCancel: () => boolean;
/**
* Notifies the remote control module about the denial of the remote control
* request.
@ -122,8 +117,6 @@ class RemoteControlAuthorizationDialog extends Component<Props> {
return true;
}
_onSubmit: () => boolean;
/**
* Notifies the remote control module that the remote control request is
* accepted.
@ -158,7 +151,7 @@ class RemoteControlAuthorizationDialog extends Component<Props> {
* _sourceType: string
* }}
*/
function _mapStateToProps(state, ownProps) {
function _mapStateToProps(state: IReduxState, ownProps: any) {
const { _displayName, participantId } = ownProps;
const participant = getParticipantById(state, participantId);
const tracks = state['features/base/tracks'];

@ -1,5 +1,3 @@
// @flow
import { VIRTUAL_BACKGROUND_TYPE } from '../../virtual-background/constants';
import {
@ -9,30 +7,35 @@ import {
timerWorkerScript
} from './TimerWorker';
export interface IBackgroundEffectOptions {
height: number;
virtualBackground: {
backgroundType?: string;
blurValue?: number;
virtualSource?: string;
};
width: number;
}
/**
* Represents a modified MediaStream that adds effects to video background.
* <tt>JitsiStreamBackgroundEffect</tt> does the processing of the original
* video stream.
*/
export default class JitsiStreamBackgroundEffect {
_model: Object;
_options: Object;
_stream: Object;
_model: any;
_options: IBackgroundEffectOptions;
_stream: any;
_segmentationPixelCount: number;
_inputVideoElement: HTMLVideoElement;
_onMaskFrameTimer: Function;
_maskFrameTimerWorker: Worker;
_outputCanvasElement: HTMLCanvasElement;
_outputCanvasCtx: Object;
_segmentationMaskCtx: Object;
_segmentationMask: Object;
_segmentationMaskCanvas: Object;
_renderMask: Function;
_outputCanvasCtx: CanvasRenderingContext2D | null;
_segmentationMaskCtx: CanvasRenderingContext2D | null;
_segmentationMask: ImageData;
_segmentationMaskCanvas: HTMLCanvasElement;
_virtualImage: HTMLImageElement;
_virtualVideo: HTMLVideoElement;
isEnabled: Function;
startEffect: Function;
stopEffect: Function;
/**
* Represents a modified video MediaStream track.
@ -41,13 +44,13 @@ export default class JitsiStreamBackgroundEffect {
* @param {Object} model - Meet model.
* @param {Object} options - Segmentation dimensions.
*/
constructor(model: Object, options: Object) {
constructor(model: Object, options: IBackgroundEffectOptions) {
this._options = options;
if (this._options.virtualBackground.backgroundType === VIRTUAL_BACKGROUND_TYPE.IMAGE) {
this._virtualImage = document.createElement('img');
this._virtualImage.crossOrigin = 'anonymous';
this._virtualImage.src = this._options.virtualBackground.virtualSource;
this._virtualImage.src = this._options.virtualBackground.virtualSource ?? '';
}
this._model = model;
this._segmentationPixelCount = this._options.width * this._options.height;
@ -68,7 +71,7 @@ export default class JitsiStreamBackgroundEffect {
* @param {EventHandler} response - The onmessage EventHandler parameter.
* @returns {void}
*/
_onMaskFrameTimer(response: Object) {
_onMaskFrameTimer(response: { data: { id: number; }; }) {
if (response.data.id === TIMEOUT_TICK) {
this._renderMask();
}
@ -85,6 +88,10 @@ export default class JitsiStreamBackgroundEffect {
const { height, width } = track.getSettings() ?? track.getConstraints();
const { backgroundType } = this._options.virtualBackground;
if (!this._outputCanvasCtx) {
return;
}
this._outputCanvasElement.height = height;
this._outputCanvasElement.width = width;
this._outputCanvasCtx.globalCompositeOperation = 'copy';
@ -93,7 +100,7 @@ export default class JitsiStreamBackgroundEffect {
// Smooth out the edges.
this._outputCanvasCtx.filter = backgroundType === VIRTUAL_BACKGROUND_TYPE.IMAGE ? 'blur(4px)' : 'blur(8px)';
this._outputCanvasCtx.drawImage(
this._outputCanvasCtx?.drawImage( // @ts-ignore
this._segmentationMaskCanvas,
0,
0,
@ -108,12 +115,13 @@ export default class JitsiStreamBackgroundEffect {
this._outputCanvasCtx.filter = 'none';
// Draw the foreground video.
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
// @ts-ignore
this._outputCanvasCtx?.drawImage(this._inputVideoElement, 0, 0);
// Draw the background.
this._outputCanvasCtx.globalCompositeOperation = 'destination-over';
if (backgroundType === VIRTUAL_BACKGROUND_TYPE.IMAGE) {
this._outputCanvasCtx.drawImage(
this._outputCanvasCtx?.drawImage( // @ts-ignore
backgroundType === VIRTUAL_BACKGROUND_TYPE.IMAGE
? this._virtualImage : this._virtualVideo,
0,
@ -123,7 +131,9 @@ export default class JitsiStreamBackgroundEffect {
);
} else {
this._outputCanvasCtx.filter = `blur(${this._options.virtualBackground.blurValue}px)`;
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
// @ts-ignore
this._outputCanvasCtx?.drawImage(this._inputVideoElement, 0, 0);
}
}
@ -143,7 +153,7 @@ export default class JitsiStreamBackgroundEffect {
this._segmentationMask.data[(i * 4) + 3] = 255 * person;
}
this._segmentationMaskCtx.putImageData(this._segmentationMask, 0, 0);
this._segmentationMaskCtx?.putImageData(this._segmentationMask, 0, 0);
}
/**
@ -169,7 +179,7 @@ export default class JitsiStreamBackgroundEffect {
* @returns {void}
*/
resizeSource() {
this._segmentationMaskCtx.drawImage(
this._segmentationMaskCtx?.drawImage( // @ts-ignore
this._inputVideoElement,
0,
0,
@ -181,7 +191,7 @@ export default class JitsiStreamBackgroundEffect {
this._options.height
);
const imageData = this._segmentationMaskCtx.getImageData(
const imageData = this._segmentationMaskCtx?.getImageData(
0,
0,
this._options.width,
@ -190,9 +200,9 @@ export default class JitsiStreamBackgroundEffect {
const inputMemoryOffset = this._model._getInputMemoryOffset() / 4;
for (let i = 0; i < this._segmentationPixelCount; i++) {
this._model.HEAPF32[inputMemoryOffset + (i * 3)] = imageData.data[i * 4] / 255;
this._model.HEAPF32[inputMemoryOffset + (i * 3) + 1] = imageData.data[(i * 4) + 1] / 255;
this._model.HEAPF32[inputMemoryOffset + (i * 3) + 2] = imageData.data[(i * 4) + 2] / 255;
this._model.HEAPF32[inputMemoryOffset + (i * 3)] = Number(imageData?.data[i * 4]) / 255;
this._model.HEAPF32[inputMemoryOffset + (i * 3) + 1] = Number(imageData?.data[(i * 4) + 1]) / 255;
this._model.HEAPF32[inputMemoryOffset + (i * 3) + 2] = Number(imageData?.data[(i * 4) + 2]) / 255;
}
}
@ -203,7 +213,7 @@ export default class JitsiStreamBackgroundEffect {
* @returns {boolean} - Returns true if this effect can run on the specified track
* false otherwise.
*/
isEnabled(jitsiLocalTrack: Object) {
isEnabled(jitsiLocalTrack: any) {
return jitsiLocalTrack.isVideoTrack() && jitsiLocalTrack.videoType === 'camera';
}

@ -56,4 +56,5 @@ const code = `
};
`;
// @ts-ignore
export const timerWorkerScript = URL.createObjectURL(new Blob([ code ], { type: 'application/javascript' }));

@ -1,17 +1,22 @@
/* eslint-disable lines-around-comment */
import { IStore } from '../../app/types';
import { showWarningNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
import { timeout } from '../../virtual-background/functions';
import logger from '../../virtual-background/logger';
import JitsiStreamBackgroundEffect from './JitsiStreamBackgroundEffect';
import JitsiStreamBackgroundEffect, { IBackgroundEffectOptions } from './JitsiStreamBackgroundEffect';
// @ts-expect-error
import createTFLiteModule from './vendor/tflite/tflite';
// @ts-expect-error
import createTFLiteSIMDModule from './vendor/tflite/tflite-simd';
const models = {
modelLandscape: 'libs/selfie_segmentation_landscape.tflite'
};
/* eslint-enable lines-around-comment */
let modelBuffer;
let tflite;
let modelBuffer: ArrayBuffer;
let tflite: any;
let wasmCheck;
let isWasmDisabled = false;
@ -31,13 +36,14 @@ const segmentationDimensions = {
* @param {Function} dispatch - The Redux dispatch function.
* @returns {Promise<JitsiStreamBackgroundEffect>}
*/
export async function createVirtualBackgroundEffect(virtualBackground: Object, dispatch: Function) {
export async function createVirtualBackgroundEffect(virtualBackground: IBackgroundEffectOptions['virtualBackground'],
dispatch?: IStore['dispatch']) {
if (!MediaStreamTrack.prototype.getSettings && !MediaStreamTrack.prototype.getConstraints) {
throw new Error('JitsiStreamBackgroundEffect not supported!');
}
if (isWasmDisabled) {
dispatch(showWarningNotification({
dispatch?.(showWarningNotification({
titleKey: 'virtualBackground.backgroundEffectError'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
@ -58,16 +64,16 @@ export async function createVirtualBackgroundEffect(virtualBackground: Object, d
} else {
tflite = await timeout(tfliteTimeout, createTFLiteModule());
}
} catch (err) {
} catch (err: any) {
if (err?.message === '408') {
logger.error('Failed to download tflite model!');
dispatch(showWarningNotification({
dispatch?.(showWarningNotification({
titleKey: 'virtualBackground.backgroundEffectError'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
} else {
isWasmDisabled = true;
logger.error('Looks like WebAssembly is disabled or not supported on this browser', err);
dispatch(showWarningNotification({
dispatch?.(showWarningNotification({
titleKey: 'virtualBackground.webAssemblyWarning',
descriptionKey: 'virtualBackground.webAssemblyWarningDescription'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));

@ -1,6 +1,4 @@
import { IStore } from '../app/types';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { createVirtualBackgroundEffect } from '../stream-effects/virtual-background';
import { BACKGROUND_ENABLED, SET_VIRTUAL_BACKGROUND } from './actionTypes';

@ -10,7 +10,7 @@ export interface IVirtualBackground {
backgroundType?: string;
blurValue?: number;
selectedThumbnail?: string;
virtualSource?: { videoType: string; };
virtualSource?: string;
}
/**

@ -33,6 +33,7 @@
"react/features/screenshot-capture",
"react/features/stream-effects/noise-suppression",
"react/features/stream-effects/rnnoise",
"react/features/stream-effects/virtual-background",
"react/features/virtual-background",
"react/features/web-hid",
"react/features/whiteboard",

Loading…
Cancel
Save