ref(TS) Convert base/tracks to TS (#12219)

This commit is contained in:
Robert Pintilii 2022-09-23 10:48:20 +03:00 committed by GitHub
parent fb2cfaa204
commit 3426960d5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 285 additions and 243 deletions

9
globals.d.ts vendored
View File

@ -1,6 +1,13 @@
import { IStore } from "./react/features/app/types";
export {};
declare global {
const APP: any;
const APP: {
store: IStore;
UI: any;
API: any;
conference: any;
};
const interfaceConfig: any;
}

View File

@ -52,6 +52,7 @@ export interface IJitsiConference {
muteParticipant: Function;
on: Function;
removeTrack: Function;
replaceTrack: Function;
sendCommand: Function;
sendEndpointMessage: Function;
sessionId: string;

View File

@ -54,7 +54,9 @@ export const VIDEO_MUTISM_AUTHORITY = {
*
* @enum {string}
*/
export const VIDEO_TYPE = {
export const VIDEO_TYPE: { [key: string]: VideoType; } = {
CAMERA: 'camera',
DESKTOP: 'desktop'
};
export type VideoType = 'camera' | 'desktop';

View File

@ -1,25 +1,26 @@
/* global APP */
import {
createTrackMutedEvent,
sendAnalytics
} from '../../analytics';
import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../../notifications';
import { getCurrentConference } from '../conference';
import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
import { createTrackMutedEvent } from '../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../analytics/functions';
import { IStore } from '../../app/types';
import { showErrorNotification, showNotification } from '../../notifications/actions';
import { NOTIFICATION_TIMEOUT, NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
import { getCurrentConference } from '../conference/functions';
import { IJitsiConference } from '../conference/reducer';
import { getMultipleVideoSendingSupportFeatureFlag } from '../config/functions.any';
import { JitsiTrackErrors, JitsiTrackEvents } from '../lib-jitsi-meet';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { createLocalTrack } from '../lib-jitsi-meet/functions';
import { setAudioMuted, setScreenshareMuted, setVideoMuted } from '../media/actions';
import {
CAMERA_FACING_MODE,
MediaType,
MEDIA_TYPE,
setAudioMuted,
setScreenshareMuted,
setVideoMuted,
VideoType,
VIDEO_MUTISM_AUTHORITY,
VIDEO_TYPE
} from '../media';
import { getLocalParticipant } from '../participants';
import { updateSettings } from '../settings';
} from '../media/constants';
import { getLocalParticipant } from '../participants/functions';
import { updateSettings } from '../settings/actions';
import {
SET_NO_SRC_DATA_NOTIFICATION_UID,
@ -43,6 +44,7 @@ import {
getTrackByJitsiTrack
} from './functions';
import logger from './logger';
import { TrackOptions } from './types';
/**
* Add a given local track to the conference.
@ -50,8 +52,8 @@ import logger from './logger';
* @param {JitsiLocalTrack} newTrack - The local track to be added to the conference.
* @returns {Function}
*/
export function addLocalTrack(newTrack) {
return async (dispatch, getState) => {
export function addLocalTrack(newTrack: any) {
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const conference = getCurrentConference(getState());
if (conference) {
@ -82,8 +84,8 @@ export function addLocalTrack(newTrack) {
*
* @returns {Function}
*/
export function createDesiredLocalTracks(...desiredTypes) {
return (dispatch, getState) => {
export function createDesiredLocalTracks(...desiredTypes: any) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState();
dispatch(destroyLocalDesktopTrackIfExists());
@ -118,7 +120,7 @@ export function createDesiredLocalTracks(...desiredTypes) {
// We need to create the desired tracks which are not already available.
const createTypes
= desiredTypes.filter(type => availableTypes.indexOf(type) === -1);
= desiredTypes.filter((type: MediaType) => availableTypes.indexOf(type) === -1);
createTypes.length
&& dispatch(createLocalTracksA({ devices: createTypes }));
@ -132,8 +134,8 @@ export function createDesiredLocalTracks(...desiredTypes) {
* @param {Object} [options] - For info @see JitsiMeetJS.createLocalTracks.
* @returns {Function}
*/
export function createLocalTracksA(options = {}) {
return (dispatch, getState) => {
export function createLocalTracksA(options: TrackOptions = {}) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const devices
= options.devices || [ MEDIA_TYPE.AUDIO, MEDIA_TYPE.VIDEO ];
const store = {
@ -154,7 +156,7 @@ export function createLocalTracksA(options = {}) {
for (const device of devices) {
if (getLocalTrack(
getState()['features/base/tracks'],
device,
device as MediaType,
/* includePending */ true)) {
throw new Error(`Local track for ${device} already exists`);
}
@ -170,7 +172,7 @@ export function createLocalTracksA(options = {}) {
},
store)
.then(
localTracks => {
(localTracks: any[]) => {
// Because GUM is called for 1 device (which is actually
// a media type 'audio', 'video', 'screen', etc.) we
// should not get more than one JitsiTrack.
@ -184,15 +186,15 @@ export function createLocalTracksA(options = {}) {
if (gumProcess.canceled) {
return _disposeTracks(localTracks)
.then(() =>
dispatch(_trackCreateCanceled(device)));
dispatch(_trackCreateCanceled(device as MediaType)));
}
return dispatch(trackAdded(localTracks[0]));
},
reason =>
(reason: Error) =>
dispatch(
gumProcess.canceled
? _trackCreateCanceled(device)
? _trackCreateCanceled(device as MediaType)
: _onCreateLocalTracksRejected(
reason,
device)));
@ -230,12 +232,12 @@ export function createLocalTracksA(options = {}) {
*/
export function destroyLocalTracks(track = null) {
if (track) {
return dispatch => {
return (dispatch: IStore['dispatch']) => {
dispatch(_disposeAndRemoveTracks([ track ]));
};
}
return (dispatch, getState) => {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
// First wait until any getUserMedia in progress is settled and then get
// rid of all local tracks.
_cancelGUMProcesses(getState)
@ -257,7 +259,7 @@ export function destroyLocalTracks(track = null) {
* track: Track
* }}
*/
export function noDataFromSource(track) {
export function noDataFromSource(track: any) {
return {
type: TRACK_NO_DATA_FROM_SOURCE,
track
@ -270,8 +272,8 @@ export function noDataFromSource(track) {
* @param {JitsiLocalTrack} jitsiTrack - The track.
* @returns {Function}
*/
export function showNoDataFromSourceVideoError(jitsiTrack) {
return async (dispatch, getState) => {
export function showNoDataFromSourceVideoError(jitsiTrack: any) {
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
let notificationInfo;
const track = getTrackByJitsiTrack(getState()['features/base/tracks'], jitsiTrack);
@ -289,7 +291,7 @@ export function showNoDataFromSourceVideoError(jitsiTrack) {
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
notificationInfo = {
uid: notificationAction.uid
uid: notificationAction?.uid
};
}
dispatch(trackNoDataFromSourceNotificationInfoChanged(jitsiTrack, notificationInfo));
@ -311,7 +313,8 @@ export function showNoDataFromSourceVideoError(jitsiTrack) {
* shareOptions: Object
* }}
*/
export function toggleScreensharing(enabled, audioOnly = false, ignoreDidHaveVideo = false, shareOptions = {}) {
export function toggleScreensharing(enabled: boolean, audioOnly = false,
ignoreDidHaveVideo = false, shareOptions = {}) {
return {
type: TOGGLE_SCREENSHARING,
enabled,
@ -333,8 +336,8 @@ export function toggleScreensharing(enabled, audioOnly = false, ignoreDidHaveVid
* will be used.
* @returns {Function}
*/
export function replaceLocalTrack(oldTrack, newTrack, conference) {
return async (dispatch, getState) => {
export function replaceLocalTrack(oldTrack: any, newTrack: any, conference?: IJitsiConference) {
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
conference
// eslint-disable-next-line no-param-reassign
@ -355,8 +358,8 @@ export function replaceLocalTrack(oldTrack, newTrack, conference) {
* @param {JitsiLocalTrack|null} newTrack - The track to use instead.
* @returns {Function}
*/
function replaceStoredTracks(oldTrack, newTrack) {
return async (dispatch, getState) => {
function replaceStoredTracks(oldTrack: any, newTrack: any) {
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
// We call dispose after doing the replace because dispose will
// try and do a new o/a after the track removes itself. Doing it
// after means the JitsiLocalTrack.conference is already
@ -395,14 +398,14 @@ function replaceStoredTracks(oldTrack, newTrack) {
* @param {(JitsiLocalTrack|JitsiRemoteTrack)} track - JitsiTrack instance.
* @returns {{ type: TRACK_ADDED, track: Track }}
*/
export function trackAdded(track) {
return async (dispatch, getState) => {
export function trackAdded(track: any) {
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
track.on(
JitsiTrackEvents.TRACK_MUTE_CHANGED,
() => dispatch(trackMutedChanged(track)));
track.on(
JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED,
type => dispatch(trackVideoTypeChanged(track, type)));
(type: VideoType) => dispatch(trackVideoTypeChanged(track, type)));
// participantId
const local = track.isLocal();
@ -434,13 +437,13 @@ export function trackAdded(track) {
// Set the notification ID so that other parts of the application know that this was
// displayed in the context of the current device.
// I.E. The no-audio-signal notification shouldn't be displayed if this was already shown.
dispatch(setNoSrcDataNotificationUid(notificationAction.uid));
dispatch(setNoSrcDataNotificationUid(notificationAction?.uid));
noDataFromSourceNotificationInfo = { uid: notificationAction.uid };
noDataFromSourceNotificationInfo = { uid: notificationAction?.uid };
} else {
const timeout = setTimeout(() => dispatch(
showNoDataFromSourceVideoError(track)),
NOTIFICATION_TIMEOUT_TYPE.MEDIUM);
NOTIFICATION_TIMEOUT.MEDIUM);
noDataFromSourceNotificationInfo = { timeout };
}
@ -486,7 +489,7 @@ export function trackAdded(track) {
* track: Track
* }}
*/
export function trackMutedChanged(track) {
export function trackMutedChanged(track: any) {
return {
type: TRACK_UPDATED,
track: {
@ -507,7 +510,7 @@ export function trackMutedChanged(track) {
* track: Track
* }}
*/
export function trackMuteUnmuteFailed(track, wasMuting) {
export function trackMuteUnmuteFailed(track: any, wasMuting: boolean) {
return {
type: TRACK_MUTE_UNMUTE_FAILED,
track,
@ -525,7 +528,7 @@ export function trackMuteUnmuteFailed(track, wasMuting) {
* track: Track
* }}
*/
export function trackNoDataFromSourceNotificationInfoChanged(track, noDataFromSourceNotificationInfo) {
export function trackNoDataFromSourceNotificationInfoChanged(track: any, noDataFromSourceNotificationInfo?: Object) {
return {
type: TRACK_UPDATED,
track: {
@ -545,7 +548,7 @@ export function trackNoDataFromSourceNotificationInfoChanged(track, noDataFromSo
* track: Track
* }}
*/
export function trackRemoved(track) {
export function trackRemoved(track: any) {
track.removeAllListeners(JitsiTrackEvents.TRACK_MUTE_CHANGED);
track.removeAllListeners(JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED);
track.removeAllListeners(JitsiTrackEvents.NO_DATA_FROM_SOURCE);
@ -567,7 +570,7 @@ export function trackRemoved(track) {
* track: Track
* }}
*/
export function trackVideoStarted(track) {
export function trackVideoStarted(track: any) {
return {
type: TRACK_UPDATED,
track: {
@ -587,7 +590,7 @@ export function trackVideoStarted(track) {
* track: Track
* }}
*/
export function trackVideoTypeChanged(track, videoType) {
export function trackVideoTypeChanged(track: any, videoType: VideoType) {
return {
type: TRACK_UPDATED,
track: {
@ -607,7 +610,7 @@ export function trackVideoTypeChanged(track, videoType) {
* track: Track
* }}
*/
export function trackStreamingStatusChanged(track, streamingStatus) {
export function trackStreamingStatusChanged(track: any, streamingStatus: string) {
return {
type: TRACK_UPDATED,
track: {
@ -624,8 +627,8 @@ export function trackStreamingStatusChanged(track, streamingStatus) {
* @private
* @returns {Function}
*/
function _addTracks(tracks) {
return dispatch => Promise.all(tracks.map(t => dispatch(trackAdded(t))));
function _addTracks(tracks: any[]) {
return (dispatch: IStore['dispatch']) => Promise.all(tracks.map(t => dispatch(trackAdded(t))));
}
/**
@ -640,16 +643,16 @@ function _addTracks(tracks) {
* about here is to be sure that the {@code getUserMedia} callbacks have
* completed (i.e. Returned from the native side).
*/
function _cancelGUMProcesses(getState) {
function _cancelGUMProcesses(getState: IStore['getState']) {
const logError
= error =>
= (error: Error) =>
logger.error('gumProcess.cancel failed', JSON.stringify(error));
return Promise.all(
getState()['features/base/tracks']
.filter(t => t.local)
.map(({ gumProcess }) =>
gumProcess && gumProcess.cancel().catch(logError)));
.map(({ gumProcess }: any) =>
gumProcess?.cancel().catch(logError)));
}
/**
@ -659,8 +662,8 @@ function _cancelGUMProcesses(getState) {
* @protected
* @returns {Function}
*/
export function _disposeAndRemoveTracks(tracks) {
return dispatch =>
export function _disposeAndRemoveTracks(tracks: any[]) {
return (dispatch: IStore['dispatch']) =>
_disposeTracks(tracks)
.then(() =>
Promise.all(tracks.map(t => dispatch(trackRemoved(t)))));
@ -674,11 +677,11 @@ export function _disposeAndRemoveTracks(tracks) {
* @returns {Promise} - A Promise resolved once {@link JitsiTrack.dispose()} is
* done for every track from the list.
*/
function _disposeTracks(tracks) {
function _disposeTracks(tracks: any) {
return Promise.all(
tracks.map(t =>
tracks.map((t: any) =>
t.dispose()
.catch(err => {
.catch((err: Error) => {
// Track might be already disposed so ignore such an error.
// Of course, re-throw any other error(s).
if (err.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) {
@ -697,8 +700,8 @@ function _disposeTracks(tracks) {
* @private
* @returns {Function}
*/
function _onCreateLocalTracksRejected(error, device) {
return dispatch => {
function _onCreateLocalTracksRejected(error: Error, device: string) {
return (dispatch: IStore['dispatch']) => {
// If permissions are not allowed, alert the user.
dispatch({
type: TRACK_CREATE_ERROR,
@ -724,11 +727,10 @@ function _onCreateLocalTracksRejected(error, device) {
* @private
* @returns {boolean}
*/
function _shouldMirror(track) {
function _shouldMirror(track: any) {
return (
track
&& track.isLocal()
&& track.isVideoTrack()
track?.isLocal()
&& track?.isVideoTrack()
// XXX The type of the return value of JitsiLocalTrack's
// getCameraFacingMode happens to be named CAMERA_FACING_MODE as
@ -736,7 +738,7 @@ function _shouldMirror(track) {
// of the value on the right side of the equality check is defined
// by jitsi-meet. The type definitions are surely compatible today
// but that may not be the case tomorrow.
&& track.getCameraFacingMode() === CAMERA_FACING_MODE.USER);
&& track?.getCameraFacingMode() === CAMERA_FACING_MODE.USER);
}
/**
@ -752,7 +754,7 @@ function _shouldMirror(track) {
* trackType: MEDIA_TYPE
* }}
*/
function _trackCreateCanceled(mediaType) {
function _trackCreateCanceled(mediaType: MediaType) {
return {
type: TRACK_CREATE_CANCELED,
trackType: mediaType
@ -765,7 +767,7 @@ function _trackCreateCanceled(mediaType) {
* @returns {Function}
*/
export function destroyLocalDesktopTrackIfExists() {
return (dispatch, getState) => {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const videoTrack = getLocalVideoTrack(getState()['features/base/tracks']);
const isDesktopTrack = videoTrack && videoTrack.videoType === VIDEO_TYPE.DESKTOP;
@ -782,10 +784,10 @@ export function destroyLocalDesktopTrackIfExists() {
* @param {number} uid - Notification UID.
* @returns {{
* type: SET_NO_AUDIO_SIGNAL_UID,
* uid: number
* uid: string
* }}
*/
export function setNoSrcDataNotificationUid(uid) {
export function setNoSrcDataNotificationUid(uid?: string) {
return {
type: SET_NO_SRC_DATA_NOTIFICATION_UID,
uid
@ -803,7 +805,7 @@ export function setNoSrcDataNotificationUid(uid) {
* name: string
* }}
*/
export function updateLastTrackVideoMediaEvent(track, name) {
export function updateLastTrackVideoMediaEvent(track: any, name: string) {
return {
type: TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
track,
@ -817,10 +819,10 @@ export function updateLastTrackVideoMediaEvent(track, name) {
* @returns {Function}
*/
export function toggleCamera() {
return async (dispatch, getState) => {
return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const state = getState();
const tracks = state['features/base/tracks'];
const localVideoTrack = getLocalVideoTrack(tracks).jitsiTrack;
const localVideoTrack = getLocalVideoTrack(tracks)?.jitsiTrack;
const currentFacingMode = localVideoTrack.getCameraFacingMode();
/**

View File

@ -1,39 +1,44 @@
/* global APP */
import { IState, IStore } from '../../app/types';
import { IStateful } from '../app/types';
import {
getMultipleVideoSendingSupportFeatureFlag,
getMultipleVideoSupportFeatureFlag
} from '../config/functions.any';
import { isMobileBrowser } from '../environment/utils';
import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
import { MEDIA_TYPE, VIDEO_TYPE, setAudioMuted } from '../media';
import { getParticipantByIdOrUndefined, getVirtualScreenshareParticipantOwnerId } from '../participants';
import { toState } from '../redux';
import { setAudioMuted } from '../media/actions';
import { MediaType, MEDIA_TYPE, VIDEO_TYPE } from '../media/constants';
import { getParticipantByIdOrUndefined, getVirtualScreenshareParticipantOwnerId } from '../participants/functions';
import { Participant } from '../participants/types';
import { toState } from '../redux/functions';
import {
getUserSelectedCameraDeviceId,
getUserSelectedMicDeviceId
} from '../settings';
} from '../settings/functions.any';
// @ts-ignore
import loadEffects from './loadEffects';
import logger from './logger';
import { ITrack } from './reducer';
import { TrackOptions } from './types';
/**
* Returns root tracks state.
*
* @param {Object} state - Global state.
* @param {IState} state - Global state.
* @returns {Object} Tracks state.
*/
export const getTrackState = state => state['features/base/tracks'];
export const getTrackState = (state: IState) => state['features/base/tracks'];
/**
* Checks if the passed media type is muted for the participant.
*
* @param {Object} participant - Participant reference.
* @param {MEDIA_TYPE} mediaType - Media type.
* @param {Object} state - Global state.
* @param {Participant} participant - Participant reference.
* @param {MediaType} mediaType - Media type.
* @param {IState} state - Global state.
* @returns {boolean} - Is the media type muted for the participant.
*/
export function isParticipantMediaMuted(participant, mediaType, state) {
export function isParticipantMediaMuted(participant: Participant, mediaType: MediaType, state: IState) {
if (!participant) {
return false;
}
@ -52,22 +57,22 @@ export function isParticipantMediaMuted(participant, mediaType, state) {
/**
* Checks if the participant is audio muted.
*
* @param {Object} participant - Participant reference.
* @param {Object} state - Global state.
* @param {Participant} participant - Participant reference.
* @param {IState} state - Global state.
* @returns {boolean} - Is audio muted for the participant.
*/
export function isParticipantAudioMuted(participant, state) {
export function isParticipantAudioMuted(participant: Participant, state: IState) {
return isParticipantMediaMuted(participant, MEDIA_TYPE.AUDIO, state);
}
/**
* Checks if the participant is video muted.
*
* @param {Object} participant - Participant reference.
* @param {Object} state - Global state.
* @param {Participant} participant - Participant reference.
* @param {IState} state - Global state.
* @returns {boolean} - Is video muted for the participant.
*/
export function isParticipantVideoMuted(participant, state) {
export function isParticipantVideoMuted(participant: Participant, state: IState) {
return isParticipantMediaMuted(participant, MEDIA_TYPE.VIDEO, state);
}
@ -83,7 +88,7 @@ export function isParticipantVideoMuted(participant, state) {
* shared.
* @returns {Promise<JitsiLocalTrack>}
*/
export async function createLocalPresenterTrack(options, desktopHeight) {
export async function createLocalPresenterTrack(options: TrackOptions, desktopHeight: number) {
const { cameraDeviceId } = options;
// compute the constraints of the camera track based on the resolution
@ -130,11 +135,11 @@ export async function createLocalPresenterTrack(options, desktopHeight) {
* @param {boolean} [options.fireSlowPromiseEvent] - Whether lib-jitsi-meet
* should check for a slow {@code getUserMedia} request and fire a
* corresponding event.
* @param {Object} store - The redux store in the context of which the function
* @param {IStore} store - The redux store in the context of which the function
* is to execute and from which state such as {@code config} is to be retrieved.
* @returns {Promise<JitsiLocalTrack[]>}
*/
export function createLocalTracksF(options = {}, store) {
export function createLocalTracksF(options: TrackOptions = {}, store?: IStore) {
let { cameraDeviceId, micDeviceId } = options;
const {
desktopSharingSourceDevice,
@ -147,7 +152,9 @@ export function createLocalTracksF(options = {}, store) {
if (typeof APP !== 'undefined') {
// TODO The app's settings should go in the redux store and then the
// reliance on the global variable APP will go away.
store || (store = APP.store); // eslint-disable-line no-param-reassign
if (!store) {
store = APP.store; // eslint-disable-line no-param-reassign
}
const state = store.getState();
@ -159,6 +166,7 @@ export function createLocalTracksF(options = {}, store) {
}
}
// @ts-ignore
const state = store.getState();
const {
desktopSharingFrameRate,
@ -168,7 +176,7 @@ export function createLocalTracksF(options = {}, store) {
const constraints = options.constraints ?? state['features/base/config'].constraints;
return (
loadEffects(store).then(effectsArray => {
loadEffects(store).then((effectsArray: Object[]) => {
// Filter any undefined values returned by Promise.resolve().
const effects = effectsArray.filter(effect => Boolean(effect));
@ -181,7 +189,7 @@ export function createLocalTracksF(options = {}, store) {
desktopSharingSources,
// Copy array to avoid mutations inside library.
devices: options.devices.slice(0),
devices: options.devices?.slice(0),
effects,
firefox_fake_device, // eslint-disable-line camelcase
firePermissionPromptIsShownEvent,
@ -190,7 +198,7 @@ export function createLocalTracksF(options = {}, store) {
resolution,
timeout
})
.catch(err => {
.catch((err: Error) => {
logger.error('Failed to create local tracks', options.devices, err);
return Promise.reject(err);
@ -207,7 +215,7 @@ export function createLocalTracksF(options = {}, store) {
* @todo Refactor to not use APP.
*/
export function createPrejoinTracks() {
const errors = {};
const errors: any = {};
const initialDevices = [ 'audio' ];
const requestedAudio = true;
let requestedVideo = false;
@ -235,8 +243,8 @@ export function createPrejoinTracks() {
tryCreateLocalTracks = createLocalTracksF({
devices: initialDevices,
firePermissionPromptIsShownEvent: true
})
.catch(err => {
}, APP.store)
.catch((err: Error) => {
if (requestedAudio && requestedVideo) {
// Try audio only...
@ -258,7 +266,7 @@ export function createPrejoinTracks() {
}
logger.error('Should never happen');
})
.catch(err => {
.catch((err: Error) => {
// Log this just in case...
if (!requestedAudio) {
logger.error('The impossible just happened', err);
@ -273,7 +281,7 @@ export function createPrejoinTracks() {
})
: [];
})
.catch(err => {
.catch((err: Error) => {
// Log this just in case...
if (!requestedVideo) {
logger.error('The impossible just happened', err);
@ -293,10 +301,10 @@ export function createPrejoinTracks() {
/**
* Returns local audio track.
*
* @param {Track[]} tracks - List of all tracks.
* @param {ITrack[]} tracks - List of all tracks.
* @returns {(Track|undefined)}
*/
export function getLocalAudioTrack(tracks) {
export function getLocalAudioTrack(tracks: ITrack[]) {
return getLocalTrack(tracks, MEDIA_TYPE.AUDIO);
}
@ -309,7 +317,7 @@ export function getLocalAudioTrack(tracks) {
* {@code jitsiTrack} property is {@code undefined}. By default a pending local track is not returned.
* @returns {(Track|undefined)}
*/
export function getLocalDesktopTrack(tracks, includePending = false) {
export function getLocalDesktopTrack(tracks: ITrack[], includePending = false) {
return (
getLocalTracks(tracks, includePending)
.find(t => t.mediaType === MEDIA_TYPE.SCREENSHARE || t.videoType === VIDEO_TYPE.DESKTOP));
@ -318,10 +326,10 @@ export function getLocalDesktopTrack(tracks, includePending = false) {
/**
* Returns the stored local desktop jitsiLocalTrack.
*
* @param {Object} state - The redux state.
* @param {IState} state - The redux state.
* @returns {JitsiLocalTrack|undefined}
*/
export function getLocalJitsiDesktopTrack(state) {
export function getLocalJitsiDesktopTrack(state: IState) {
const track = getLocalDesktopTrack(getTrackState(state));
return track?.jitsiTrack;
@ -330,8 +338,8 @@ export function getLocalJitsiDesktopTrack(state) {
/**
* Returns local track by media type.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - Media type.
* @param {ITrack[]} tracks - List of all tracks.
* @param {MediaType} mediaType - Media type.
* @param {boolean} [includePending] - Indicates whether a local track is to be
* returned if it is still pending. A local track is pending if
* {@code getUserMedia} is still executing to create it and, consequently, its
@ -339,7 +347,7 @@ export function getLocalJitsiDesktopTrack(state) {
* track is not returned.
* @returns {(Track|undefined)}
*/
export function getLocalTrack(tracks, mediaType, includePending = false) {
export function getLocalTrack(tracks: ITrack[], mediaType: MediaType, includePending = false) {
return (
getLocalTracks(tracks, includePending)
.find(t => t.mediaType === mediaType));
@ -349,7 +357,7 @@ export function getLocalTrack(tracks, mediaType, includePending = false) {
* Returns an array containing the local tracks with or without a (valid)
* {@code JitsiTrack}.
*
* @param {Track[]} tracks - An array containing all local tracks.
* @param {ITrack[]} tracks - An array containing all local tracks.
* @param {boolean} [includePending] - Indicates whether a local track is to be
* returned if it is still pending. A local track is pending if
* {@code getUserMedia} is still executing to create it and, consequently, its
@ -357,7 +365,7 @@ export function getLocalTrack(tracks, mediaType, includePending = false) {
* track is not returned.
* @returns {Track[]}
*/
export function getLocalTracks(tracks, includePending = false) {
export function getLocalTracks(tracks: ITrack[], includePending = false) {
// XXX A local track is considered ready only once it has its `jitsiTrack`
// property set by the `TRACK_ADDED` action. Until then there is a stub
// added just before the `getUserMedia` call with a cancellable
@ -371,20 +379,20 @@ export function getLocalTracks(tracks, includePending = false) {
/**
* Returns local video track.
*
* @param {Track[]} tracks - List of all tracks.
* @param {ITrack[]} tracks - List of all tracks.
* @returns {(Track|undefined)}
*/
export function getLocalVideoTrack(tracks) {
export function getLocalVideoTrack(tracks: ITrack[]) {
return getLocalTrack(tracks, MEDIA_TYPE.VIDEO);
}
/**
* Returns the media type of the local video, presenter or video.
*
* @param {Track[]} tracks - List of all tracks.
* @param {ITrack[]} tracks - List of all tracks.
* @returns {MEDIA_TYPE}
*/
export function getLocalVideoType(tracks) {
export function getLocalVideoType(tracks: ITrack[]) {
const presenterTrack = getLocalTrack(tracks, MEDIA_TYPE.PRESENTER);
return presenterTrack ? MEDIA_TYPE.PRESENTER : MEDIA_TYPE.VIDEO;
@ -393,10 +401,10 @@ export function getLocalVideoType(tracks) {
/**
* Returns the stored local video track.
*
* @param {Object} state - The redux state.
* @param {IState} state - The redux state.
* @returns {Object}
*/
export function getLocalJitsiVideoTrack(state) {
export function getLocalJitsiVideoTrack(state: IState) {
const track = getLocalVideoTrack(getTrackState(state));
return track?.jitsiTrack;
@ -405,10 +413,10 @@ export function getLocalJitsiVideoTrack(state) {
/**
* Returns the stored local audio track.
*
* @param {Object} state - The redux state.
* @param {IState} state - The redux state.
* @returns {Object}
*/
export function getLocalJitsiAudioTrack(state) {
export function getLocalJitsiAudioTrack(state: IState) {
const track = getLocalAudioTrack(getTrackState(state));
return track?.jitsiTrack;
@ -417,13 +425,13 @@ export function getLocalJitsiAudioTrack(state) {
/**
* Returns track of specified media type for specified participant.
*
* @param {Track[]} tracks - List of all tracks.
* @param {Object} participant - Participant Object.
* @param {ITrack[]} tracks - List of all tracks.
* @param {Participant} participant - Participant Object.
* @returns {(Track|undefined)}
*/
export function getVideoTrackByParticipant(
tracks,
participant) {
tracks: ITrack[],
participant?: Participant) {
if (!participant) {
return;
@ -439,11 +447,11 @@ export function getVideoTrackByParticipant(
/**
* Returns source name for specified participant id.
*
* @param {Object} state - The Redux state.
* @param {IState} state - The Redux state.
* @param {string} participantId - Participant ID.
* @returns {string | undefined}
*/
export function getSourceNameByParticipantId(state, participantId) {
export function getSourceNameByParticipantId(state: IState, participantId: string) {
const participant = getParticipantByIdOrUndefined(state, participantId);
const tracks = state['features/base/tracks'];
const track = getVideoTrackByParticipant(tracks, participant);
@ -454,15 +462,15 @@ export function getSourceNameByParticipantId(state, participantId) {
/**
* Returns track of specified media type for specified participant id.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - Media type.
* @param {ITrack[]} tracks - List of all tracks.
* @param {MediaType} mediaType - Media type.
* @param {string} participantId - Participant ID.
* @returns {(Track|undefined)}
*/
export function getTrackByMediaTypeAndParticipant(
tracks,
mediaType,
participantId) {
tracks: ITrack[],
mediaType: MediaType,
participantId: string) {
return tracks.find(
t => Boolean(t.jitsiTrack) && t.participantId === participantId && t.mediaType === mediaType
);
@ -471,11 +479,11 @@ export function getTrackByMediaTypeAndParticipant(
/**
* Returns screenshare track of given virtualScreenshareParticipantId.
*
* @param {Track[]} tracks - List of all tracks.
* @param {ITrack[]} tracks - List of all tracks.
* @param {string} virtualScreenshareParticipantId - Virtual Screenshare Participant ID.
* @returns {(Track|undefined)}
*/
export function getVirtualScreenshareParticipantTrack(tracks, virtualScreenshareParticipantId) {
export function getVirtualScreenshareParticipantTrack(tracks: ITrack[], virtualScreenshareParticipantId: string) {
const ownderId = getVirtualScreenshareParticipantOwnerId(virtualScreenshareParticipantId);
return getScreenShareTrack(tracks, ownderId);
@ -484,16 +492,16 @@ export function getVirtualScreenshareParticipantTrack(tracks, virtualScreenshare
/**
* Returns track source names of given screen share participant ids.
*
* @param {Object} state - The entire redux state.
* @param {IState} state - The entire redux state.
* @param {string[]} screenShareParticipantIds - Participant ID.
* @returns {(string[])}
*/
export function getRemoteScreenSharesSourceNames(state, screenShareParticipantIds = []) {
export function getRemoteScreenSharesSourceNames(state: IState, screenShareParticipantIds = []) {
const tracks = state['features/base/tracks'];
return getMultipleVideoSupportFeatureFlag(state)
? screenShareParticipantIds
: screenShareParticipantIds.reduce((acc, id) => {
: screenShareParticipantIds.reduce((acc: string[], id) => {
const sourceName = getScreenShareTrack(tracks, id)?.jitsiTrack.getSourceName();
if (sourceName) {
@ -511,7 +519,7 @@ export function getRemoteScreenSharesSourceNames(state, screenShareParticipantId
* @param {string} ownerId - Screenshare track owner ID.
* @returns {(Track|undefined)}
*/
export function getScreenShareTrack(tracks, ownerId) {
export function getScreenShareTrack(tracks: ITrack[], ownerId: string) {
return tracks.find(
t => Boolean(t.jitsiTrack)
&& t.participantId === ownerId
@ -522,15 +530,15 @@ export function getScreenShareTrack(tracks, ownerId) {
/**
* Returns track source name of specified media type for specified participant id.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - Media type.
* @param {ITrack[]} tracks - List of all tracks.
* @param {MediaType} mediaType - Media type.
* @param {string} participantId - Participant ID.
* @returns {(string|undefined)}
*/
export function getTrackSourceNameByMediaTypeAndParticipant(
tracks,
mediaType,
participantId) {
tracks: ITrack[],
mediaType: MediaType,
participantId: string) {
const track = getTrackByMediaTypeAndParticipant(
tracks,
mediaType,
@ -543,32 +551,32 @@ export function getTrackSourceNameByMediaTypeAndParticipant(
* Returns the track if any which corresponds to a specific instance
* of JitsiLocalTrack or JitsiRemoteTrack.
*
* @param {Track[]} tracks - List of all tracks.
* @param {ITrack[]} tracks - List of all tracks.
* @param {(JitsiLocalTrack|JitsiRemoteTrack)} jitsiTrack - JitsiTrack instance.
* @returns {(Track|undefined)}
*/
export function getTrackByJitsiTrack(tracks, jitsiTrack) {
export function getTrackByJitsiTrack(tracks: ITrack[], jitsiTrack: any) {
return tracks.find(t => t.jitsiTrack === jitsiTrack);
}
/**
* Returns tracks of specified media type.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - Media type.
* @param {ITrack[]} tracks - List of all tracks.
* @param {MediaType} mediaType - Media type.
* @returns {Track[]}
*/
export function getTracksByMediaType(tracks, mediaType) {
export function getTracksByMediaType(tracks: ITrack[], mediaType: MediaType) {
return tracks.filter(t => t.mediaType === mediaType);
}
/**
* Checks if the local video camera track in the given set of tracks is muted.
*
* @param {Track[]} tracks - List of all tracks.
* @returns {Track[]}
* @param {ITrack[]} tracks - List of all tracks.
* @returns {ITrack[]}
*/
export function isLocalCameraTrackMuted(tracks) {
export function isLocalCameraTrackMuted(tracks: ITrack[]) {
const presenterTrack = getLocalTrack(tracks, MEDIA_TYPE.PRESENTER);
const videoTrack = getLocalTrack(tracks, MEDIA_TYPE.VIDEO);
@ -588,13 +596,13 @@ export function isLocalCameraTrackMuted(tracks) {
/**
* Checks if the first local track in the given tracks set is muted.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - The media type of tracks to be checked.
* @param {ITrack[]} tracks - List of all tracks.
* @param {MediaType} mediaType - The media type of tracks to be checked.
* @returns {boolean} True if local track is muted or false if the track is
* unmuted or if there are no local tracks of the given media type in the given
* set of tracks.
*/
export function isLocalTrackMuted(tracks, mediaType) {
export function isLocalTrackMuted(tracks: ITrack[], mediaType: MediaType) {
const track = getLocalTrack(tracks, mediaType);
return !track || track.muted;
@ -603,10 +611,10 @@ export function isLocalTrackMuted(tracks, mediaType) {
/**
* Checks if the local video track is of type DESKtOP.
*
* @param {Object} state - The redux state.
* @param {IState} state - The redux state.
* @returns {boolean}
*/
export function isLocalVideoTrackDesktop(state) {
export function isLocalVideoTrackDesktop(state: IState) {
const videoTrack = getLocalVideoTrack(getTrackState(state));
return videoTrack && videoTrack.videoType === VIDEO_TYPE.DESKTOP;
@ -617,12 +625,12 @@ export function isLocalVideoTrackDesktop(state) {
* Returns true if the remote track of the given media type and the given
* participant is muted, false otherwise.
*
* @param {Track[]} tracks - List of all tracks.
* @param {MEDIA_TYPE} mediaType - The media type of tracks to be checked.
* @param {*} participantId - Participant ID.
* @param {ITrack[]} tracks - List of all tracks.
* @param {MediaType} mediaType - The media type of tracks to be checked.
* @param {string} participantId - Participant ID.
* @returns {boolean}
*/
export function isRemoteTrackMuted(tracks, mediaType, participantId) {
export function isRemoteTrackMuted(tracks: ITrack[], mediaType: MediaType, participantId: string) {
const track = getTrackByMediaTypeAndParticipant(
tracks, mediaType, participantId);
@ -633,10 +641,10 @@ export function isRemoteTrackMuted(tracks, mediaType, participantId) {
* Returns whether or not the current environment needs a user interaction with
* the page before any unmute can occur.
*
* @param {Object} state - The redux state.
* @param {IState} state - The redux state.
* @returns {boolean}
*/
export function isUserInteractionRequiredForUnmute(state) {
export function isUserInteractionRequiredForUnmute(state: IState) {
return browser.isUserInteractionRequiredForUnmute()
&& window
&& window.self !== window.top
@ -652,7 +660,7 @@ export function isUserInteractionRequiredForUnmute(state) {
* @param {Object} state - The redux state.
* @returns {Promise}
*/
export function setTrackMuted(track, muted, state) {
export function setTrackMuted(track: any, muted: boolean, state: IState) {
muted = Boolean(muted); // eslint-disable-line no-param-reassign
// Ignore the check for desktop track muted operation. When the screenshare is terminated by clicking on the
@ -665,7 +673,7 @@ export function setTrackMuted(track, muted, state) {
const f = muted ? 'mute' : 'unmute';
return track[f]().catch(error => {
return track[f]().catch((error: Error) => {
// Track might be already disposed so ignore such an error.
if (error.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) {
logger.error(`set track ${f} failed`, error);
@ -681,9 +689,9 @@ export function setTrackMuted(track, muted, state) {
* @param {Function|Object} stateful - The redux store or {@code getState} function.
* @returns {boolean} - Whether toggle camera should be enabled.
*/
export function isToggleCameraEnabled(stateful) {
export function isToggleCameraEnabled(stateful: IStateful) {
const state = toState(stateful);
const { videoInput } = state['features/base/devices'].availableDevices;
return isMobileBrowser() && videoInput.length > 1;
return isMobileBrowser() && Number(videoInput?.length) > 1;
}

View File

@ -1,28 +1,30 @@
// @flow
import { batch } from 'react-redux';
import { IStore } from '../../app/types';
import { _RESET_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
import { hideNotification } from '../../notifications';
import { hideNotification } from '../../notifications/actions';
import { isPrejoinPageVisible } from '../../prejoin/functions';
import { getCurrentConference } from '../conference/functions';
import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
import { getMultipleVideoSendingSupportFeatureFlag } from '../config/functions.any';
import { getAvailableDevices } from '../devices/actions';
import {
CAMERA_FACING_MODE,
MEDIA_TYPE,
SET_AUDIO_MUTED,
SET_CAMERA_FACING_MODE,
SET_VIDEO_MUTED,
VIDEO_MUTISM_AUTHORITY,
TOGGLE_CAMERA_FACING_MODE,
toggleCameraFacingMode,
SET_SCREENSHARE_MUTED,
SET_SCREENSHARE_MUTED
} from '../media/actionTypes';
import { toggleCameraFacingMode, setScreenshareMuted } from '../media/actions';
import {
CAMERA_FACING_MODE,
MEDIA_TYPE,
VIDEO_MUTISM_AUTHORITY,
VIDEO_TYPE,
setScreenshareMuted,
SCREENSHARE_MUTISM_AUTHORITY
} from '../media';
import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
SCREENSHARE_MUTISM_AUTHORITY,
MediaType
} from '../media/constants';
import MiddlewareRegistry from '../redux/MiddlewareRegistry';
import StateListenerRegistry from '../redux/StateListenerRegistry';
import {
TRACK_ADDED,
@ -47,11 +49,10 @@ import {
isUserInteractionRequiredForUnmute,
setTrackMuted
} from './functions';
import { ITrack } from './reducer';
import './subscriber';
declare var APP: Object;
/**
* Middleware that captures LIB_DID_DISPOSE and LIB_DID_INIT actions and,
* respectively, creates/destroys local media tracks. Also listens to
@ -267,7 +268,7 @@ StateListenerRegistry.register(
* @private
* @returns {void}
*/
function _handleNoDataFromSourceErrors(store, action) {
function _handleNoDataFromSourceErrors(store: IStore, action: any) {
const { getState, dispatch } = store;
const track = getTrackByJitsiTrack(getState()['features/base/tracks'], action.track.jitsiTrack);
@ -323,9 +324,9 @@ function _handleNoDataFromSourceErrors(store, action) {
* {@code mediaType} in the specified {@code store}.
*/
function _getLocalTrack(
{ getState }: { getState: Function },
mediaType: MEDIA_TYPE,
includePending: boolean = false) {
{ getState }: { getState: Function; },
mediaType: MediaType,
includePending = false) {
return (
getLocalTrack(
getState()['features/base/tracks'],
@ -340,11 +341,11 @@ function _getLocalTrack(
* @param {Track} track - The redux action dispatched in the specified store.
* @returns {void}
*/
function _removeNoDataFromSourceNotification({ getState, dispatch }, track) {
function _removeNoDataFromSourceNotification({ getState, dispatch }: IStore, track: ITrack) {
const t = getTrackByJitsiTrack(getState()['features/base/tracks'], track.jitsiTrack);
const { jitsiTrack, noDataFromSourceNotificationInfo = {} } = t || {};
if (noDataFromSourceNotificationInfo && noDataFromSourceNotificationInfo.uid) {
if (noDataFromSourceNotificationInfo?.uid) {
dispatch(hideNotification(noDataFromSourceNotificationInfo.uid));
dispatch(trackNoDataFromSourceNotificationInfoChanged(jitsiTrack, undefined));
}
@ -361,7 +362,8 @@ function _removeNoDataFromSourceNotification({ getState, dispatch }, track) {
* @private
* @returns {void}
*/
async function _setMuted(store, { ensureTrack, authority, muted }, mediaType: MEDIA_TYPE) {
async function _setMuted(store: IStore, { ensureTrack, authority, muted }: {
authority: number; ensureTrack: boolean; muted: boolean; }, mediaType: MediaType) {
const { dispatch, getState } = store;
const localTrack = _getLocalTrack(store, mediaType, /* includePending */ true);
const state = getState();

View File

@ -1,3 +1,4 @@
import { MediaType } from '../media/constants';
import { PARTICIPANT_ID_CHANGED } from '../participants/actionTypes';
import ReducerRegistry from '../redux/ReducerRegistry';
import { set } from '../redux/functions';
@ -14,14 +15,18 @@ import {
TRACK_WILL_CREATE
} from './actionTypes';
interface ITrack {
export interface ITrack {
isReceivingData: boolean;
jitsiTrack: any;
lastMediaEvent?: string;
local: boolean;
mediaType: string;
mediaType: MediaType;
mirror: boolean;
muted: boolean;
noDataFromSourceNotificationInfo?: {
timeout?: number;
uid?: string;
};
participantId: string;
streamingStatus?: string;
videoStarted: boolean;

View File

@ -1,13 +1,9 @@
// @flow
import _ from 'lodash';
import { StateListenerRegistry } from '../../base/redux';
import StateListenerRegistry from '../redux/StateListenerRegistry';
import { isLocalCameraTrackMuted } from './functions';
declare var APP: Object;
/**
* Notifies when the list of currently sharing participants changes.
*/

View File

@ -0,0 +1,20 @@
export interface TrackOptions {
cameraDeviceId?: string | null;
constraints?: {
video?: {
height?: {
ideal?: number;
max?: number;
min?: number;
};
};
};
desktopSharingSourceDevice?: string;
desktopSharingSources?: string[];
devices?: string[];
facingMode?: string;
firePermissionPromptIsShownEvent?: boolean;
fireSlowPromiseEvent?: boolean;
micDeviceId?: string | null;
timeout?: number;
}

View File

@ -64,7 +64,7 @@ const Prejoin: React.FC<PrejoinProps> = ({ navigation }: PrejoinProps) => {
(state: IState) => state['features/base/responsive-ui']?.aspectRatio
);
const localParticipant = useSelector((state: IState) => getLocalParticipant(state));
const isDisplayNameMandatory = useSelector(state => isDisplayNameRequired(state));
const isDisplayNameMandatory = useSelector((state: IState) => isDisplayNameRequired(state));
const roomName = useSelector((state: IState) => getConferenceName(state));
const participantName = localParticipant?.name;
const [ displayName, setDisplayName ]

View File

@ -1,26 +1,25 @@
// @flow
import { getRoomName } from '../base/conference';
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions';
import { isAudioMuted, isVideoMutedByUser } from '../base/media';
import { IState } from '../app/types';
import { getRoomName } from '../base/conference/functions';
import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions.web';
import { isAudioMuted, isVideoMutedByUser } from '../base/media/functions';
/**
* Selector for the visibility of the 'join by phone' button.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function isJoinByPhoneButtonVisible(state: Object): boolean {
export function isJoinByPhoneButtonVisible(state: IState): boolean {
return Boolean(getDialOutUrl(state) && getDialOutStatusUrl(state));
}
/**
* Selector for determining if the device status strip is visible or not.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function isDeviceStatusVisible(state: Object): boolean {
export function isDeviceStatusVisible(state: IState): boolean {
return !(isAudioMuted(state) && isVideoMutedByUser(state))
&& !state['features/base/config'].startSilent;
}
@ -28,91 +27,91 @@ export function isDeviceStatusVisible(state: Object): boolean {
/**
* Selector for determining if the display name is mandatory.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function isDisplayNameRequired(state: Object): boolean {
return state['features/prejoin']?.isDisplayNameRequired
|| state['features/base/config']?.requireDisplayName;
export function isDisplayNameRequired(state: IState): boolean {
return Boolean(state['features/prejoin']?.isDisplayNameRequired
|| state['features/base/config']?.requireDisplayName);
}
/**
* Selector for determining if the prejoin display name field is visible.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function isPrejoinDisplayNameVisible(state: Object): boolean {
export function isPrejoinDisplayNameVisible(state: IState): boolean {
return !state['features/base/config'].prejoinConfig?.hideDisplayName;
}
/**
* Returns the text for the prejoin status bar.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getDeviceStatusText(state: Object): string {
export function getDeviceStatusText(state: IState): string {
return state['features/prejoin']?.deviceStatusText;
}
/**
* Returns the type of the prejoin status bar: 'ok'|'warning'.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getDeviceStatusType(state: Object): string {
export function getDeviceStatusType(state: IState): string {
return state['features/prejoin']?.deviceStatusType;
}
/**
* Returns the 'conferenceUrl' used for dialing out.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getDialOutConferenceUrl(state: Object): string {
return `${getRoomName(state)}@${state['features/base/config'].hosts.muc}`;
export function getDialOutConferenceUrl(state: IState): string {
return `${getRoomName(state)}@${state['features/base/config'].hosts?.muc}`;
}
/**
* Selector for getting the dial out country.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {Object}
*/
export function getDialOutCountry(state: Object): Object {
export function getDialOutCountry(state: IState) {
return state['features/prejoin'].dialOutCountry;
}
/**
* Selector for getting the dial out number (without prefix).
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getDialOutNumber(state: Object): string {
export function getDialOutNumber(state: IState): string {
return state['features/prejoin'].dialOutNumber;
}
/**
* Selector for getting the dial out status while calling.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getDialOutStatus(state: Object): string {
export function getDialOutStatus(state: IState): string {
return state['features/prejoin'].dialOutStatus;
}
/**
* Returns the full dial out number (containing country code and +).
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getFullDialOutNumber(state: Object): string {
export function getFullDialOutNumber(state: IState): string {
const dialOutNumber = getDialOutNumber(state);
const country = getDialOutCountry(state);
@ -122,20 +121,20 @@ export function getFullDialOutNumber(state: Object): string {
/**
* Selector for getting the error if any while creating streams.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {string}
*/
export function getRawError(state: Object): string {
export function getRawError(state: IState): string {
return state['features/prejoin']?.rawError;
}
/**
* Selector for getting the visibility state for the 'JoinByPhoneDialog'.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function isJoinByPhoneDialogVisible(state: Object): boolean {
export function isJoinByPhoneDialogVisible(state: IState): boolean {
return state['features/prejoin']?.showJoinByPhoneDialog;
}
@ -143,28 +142,28 @@ export function isJoinByPhoneDialogVisible(state: Object): boolean {
* Returns true if the prejoin page is enabled and no flag
* to bypass showing the page is present.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function isPrejoinPageVisible(state: Object): boolean {
return navigator.product !== 'ReactNative'
export function isPrejoinPageVisible(state: IState): boolean {
return Boolean(navigator.product !== 'ReactNative'
&& state['features/base/config'].prejoinConfig?.enabled
&& state['features/prejoin']?.showPrejoin
&& !(state['features/base/config'].enableForcedReload && state['features/prejoin'].skipPrejoinOnReload);
&& !(state['features/base/config'].enableForcedReload && state['features/prejoin'].skipPrejoinOnReload));
}
/**
* Returns true if we should auto-knock in case lobby is enabled for the room.
*
* @param {Object} state - The state of the app.
* @param {IState} state - The state of the app.
* @returns {boolean}
*/
export function shouldAutoKnock(state: Object): boolean {
export function shouldAutoKnock(state: IState): boolean {
const { iAmRecorder, iAmSipGateway, autoKnockLobby, prejoinConfig } = state['features/base/config'];
const { userSelectedSkipPrejoin } = state['features/base/settings'];
const isPrejoinEnabled = prejoinConfig?.enabled;
return ((isPrejoinEnabled && !userSelectedSkipPrejoin)
return Boolean(((isPrejoinEnabled && !userSelectedSkipPrejoin)
|| autoKnockLobby || (iAmRecorder && iAmSipGateway))
&& !state['features/lobby'].knocking;
&& !state['features/lobby'].knocking);
}