2022-06-21 06:53:07 +00:00
|
|
|
import { sha512_256 as sha512 } from 'js-sha512';
|
2019-05-29 07:53:12 +00:00
|
|
|
import _ from 'lodash';
|
|
|
|
|
2022-09-19 07:40:03 +00:00
|
|
|
// @ts-ignore
|
2021-08-04 10:56:07 +00:00
|
|
|
import { getName } from '../../app/functions';
|
2022-09-19 07:40:03 +00:00
|
|
|
import { IState, IStore } from '../../app/types';
|
2021-08-09 09:29:50 +00:00
|
|
|
import { determineTranscriptionLanguage } from '../../transcribing/functions';
|
2022-09-19 07:40:03 +00:00
|
|
|
import { IStateful } from '../app/types';
|
2017-10-13 19:31:05 +00:00
|
|
|
import { JitsiTrackErrors } from '../lib-jitsi-meet';
|
2018-08-16 15:11:06 +00:00
|
|
|
import {
|
|
|
|
hiddenParticipantJoined,
|
|
|
|
hiddenParticipantLeft,
|
|
|
|
participantJoined,
|
|
|
|
participantLeft
|
2022-09-19 07:40:03 +00:00
|
|
|
} from '../participants/actions';
|
|
|
|
import { getLocalParticipant } from '../participants/functions';
|
|
|
|
import { toState } from '../redux/functions';
|
|
|
|
import { getJitsiMeetGlobalNS } from '../util/helpers';
|
|
|
|
import { getBackendSafePath, safeDecodeURIComponent } from '../util/uri';
|
2017-10-13 19:31:05 +00:00
|
|
|
|
2022-09-19 07:40:03 +00:00
|
|
|
// @ts-ignore
|
2022-06-21 06:53:07 +00:00
|
|
|
import { setObfuscatedRoom } from './actions';
|
2017-10-06 17:52:23 +00:00
|
|
|
import {
|
|
|
|
AVATAR_URL_COMMAND,
|
fix(base/participants): ensure default local id outside of conference
Makes sure that whenever a conference is left or switched, the local
participant's id will be equal to the default value.
The problem fixed by this commit is a situation where the local
participant may end up sharing the same ID with it's "ghost" when
rejoining a disconnected conference. The most important and easiest to
hit case is when the conference is left after the CONFERENCE_FAILED
event.
Another rare and harder to encounter in the real world issue is
where CONFERENCE_LEFT may come with the delay due to it's asynchronous
nature. The step by step scenario is as follows: trying to leave a
conference, but the network is not doing well, so it takes time,
requests are timing out. After getting back to the welcome page the
the CONFERENCE_LEFT has not arrived yet. The same conference is joined
again and the load config may timeout, but it will be read from the
cache. Now the network gets better and conference is joining which
results in our ghost participant added to the redux state. At this point
there's the root issue: two participants with the same id, because the
local one was neither cleared nor set to the new one yet
(PARTICIPANT_JOINED come, before CONFERENCE_JOINED where we adjust the
id). Then comes CONFERENCE_JOINED and we try to update our local id.
We're updating the ID of both ghost and local participant. It could be
also that the delayed CONFERENCE_LEFT comes for the old conference, but
it's too late and it would update the id for both participants.
The approach here reasons that the ID of the local participant
may be reset as soon as the local participant and, respectively, her ID
is no longer involved in a recoverable JitsiConference of interest to
the user and, consequently, the app.
Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
Co-authored-by: Lyubo Marinov <lmarinov@atlassian.com>
2018-05-16 20:08:34 +00:00
|
|
|
EMAIL_COMMAND,
|
2020-08-19 21:38:10 +00:00
|
|
|
JITSI_CONFERENCE_URL_KEY
|
2017-10-06 17:52:23 +00:00
|
|
|
} from './constants';
|
2019-08-21 14:50:00 +00:00
|
|
|
import logger from './logger';
|
2022-09-19 07:40:03 +00:00
|
|
|
import { IJitsiConference } from './reducer';
|
2018-07-30 14:38:25 +00:00
|
|
|
|
2021-04-21 13:48:05 +00:00
|
|
|
/**
|
|
|
|
* Returns root conference state.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IState} state - Global state.
|
2021-04-21 13:48:05 +00:00
|
|
|
* @returns {Object} Conference state.
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export const getConferenceState = (state: IState) => state['features/base/conference'];
|
2021-04-21 13:48:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Is the conference joined or not.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IState} state - Global state.
|
2021-04-21 13:48:05 +00:00
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export const getIsConferenceJoined = (state: IState) => Boolean(getConferenceState(state).conference);
|
2021-04-21 13:48:05 +00:00
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
|
|
|
* Attach a set of local tracks to a conference.
|
|
|
|
*
|
|
|
|
* @param {JitsiConference} conference - Conference instance.
|
|
|
|
* @param {JitsiLocalTrack[]} localTracks - List of local media tracks.
|
2017-09-28 21:25:04 +00:00
|
|
|
* @protected
|
2016-10-05 14:36:59 +00:00
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
2017-10-13 19:31:05 +00:00
|
|
|
export function _addLocalTracksToConference(
|
2022-09-19 07:40:03 +00:00
|
|
|
conference: IJitsiConference,
|
2017-10-13 19:31:05 +00:00
|
|
|
localTracks: Array<Object>) {
|
2016-10-05 14:36:59 +00:00
|
|
|
const conferenceLocalTracks = conference.getLocalTracks();
|
|
|
|
const promises = [];
|
|
|
|
|
|
|
|
for (const track of localTracks) {
|
|
|
|
// XXX The library lib-jitsi-meet may be draconian, for example, when
|
|
|
|
// adding one and the same video track multiple times.
|
|
|
|
if (conferenceLocalTracks.indexOf(track) === -1) {
|
2017-02-15 17:19:36 +00:00
|
|
|
promises.push(
|
2022-09-19 07:40:03 +00:00
|
|
|
conference.addTrack(track).catch((err: Error) => {
|
2016-10-05 14:36:59 +00:00
|
|
|
_reportError(
|
|
|
|
'Failed to add local track to conference',
|
|
|
|
err);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.all(promises);
|
|
|
|
}
|
|
|
|
|
2018-08-16 15:11:06 +00:00
|
|
|
/**
|
|
|
|
* Logic shared between web and RN which processes the {@code USER_JOINED}
|
|
|
|
* conference event and dispatches either {@link participantJoined} or
|
|
|
|
* {@link hiddenParticipantJoined}.
|
|
|
|
*
|
|
|
|
* @param {Object} store - The redux store.
|
|
|
|
* @param {JitsiMeetConference} conference - The conference for which the
|
|
|
|
* {@code USER_JOINED} event is being processed.
|
|
|
|
* @param {JitsiParticipant} user - The user who has just joined.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
export function commonUserJoinedHandling(
|
2022-09-19 07:40:03 +00:00
|
|
|
{ dispatch }: IStore,
|
|
|
|
conference: IJitsiConference,
|
|
|
|
user: any) {
|
2018-08-16 15:11:06 +00:00
|
|
|
const id = user.getId();
|
|
|
|
const displayName = user.getDisplayName();
|
|
|
|
|
|
|
|
if (user.isHidden()) {
|
|
|
|
dispatch(hiddenParticipantJoined(id, displayName));
|
|
|
|
} else {
|
2022-09-19 07:40:03 +00:00
|
|
|
const isReplacing = user?.isReplacing();
|
2021-06-11 08:58:45 +00:00
|
|
|
|
2018-08-16 15:11:06 +00:00
|
|
|
dispatch(participantJoined({
|
|
|
|
botType: user.getBotType(),
|
2020-10-28 20:06:59 +00:00
|
|
|
connectionStatus: user.getConnectionStatus(),
|
2018-08-16 15:11:06 +00:00
|
|
|
conference,
|
|
|
|
id,
|
|
|
|
name: displayName,
|
|
|
|
presence: user.getStatus(),
|
2021-06-11 08:58:45 +00:00
|
|
|
role: user.getRole(),
|
|
|
|
isReplacing
|
2018-08-16 15:11:06 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Logic shared between web and RN which processes the {@code USER_LEFT}
|
|
|
|
* conference event and dispatches either {@link participantLeft} or
|
|
|
|
* {@link hiddenParticipantLeft}.
|
|
|
|
*
|
|
|
|
* @param {Object} store - The redux store.
|
|
|
|
* @param {JitsiMeetConference} conference - The conference for which the
|
|
|
|
* {@code USER_LEFT} event is being processed.
|
|
|
|
* @param {JitsiParticipant} user - The user who has just left.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
export function commonUserLeftHandling(
|
2022-09-19 07:40:03 +00:00
|
|
|
{ dispatch }: IStore,
|
|
|
|
conference: IJitsiConference,
|
|
|
|
user: any) {
|
2018-08-16 15:11:06 +00:00
|
|
|
const id = user.getId();
|
|
|
|
|
|
|
|
if (user.isHidden()) {
|
|
|
|
dispatch(hiddenParticipantLeft(id));
|
|
|
|
} else {
|
2022-09-19 07:40:03 +00:00
|
|
|
const isReplaced = user.isReplaced?.();
|
2021-06-11 08:58:45 +00:00
|
|
|
|
2022-09-06 06:51:38 +00:00
|
|
|
dispatch(participantLeft(id, conference, { isReplaced }));
|
2018-08-16 15:11:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
fix(base/participants): ensure default local id outside of conference
Makes sure that whenever a conference is left or switched, the local
participant's id will be equal to the default value.
The problem fixed by this commit is a situation where the local
participant may end up sharing the same ID with it's "ghost" when
rejoining a disconnected conference. The most important and easiest to
hit case is when the conference is left after the CONFERENCE_FAILED
event.
Another rare and harder to encounter in the real world issue is
where CONFERENCE_LEFT may come with the delay due to it's asynchronous
nature. The step by step scenario is as follows: trying to leave a
conference, but the network is not doing well, so it takes time,
requests are timing out. After getting back to the welcome page the
the CONFERENCE_LEFT has not arrived yet. The same conference is joined
again and the load config may timeout, but it will be read from the
cache. Now the network gets better and conference is joining which
results in our ghost participant added to the redux state. At this point
there's the root issue: two participants with the same id, because the
local one was neither cleared nor set to the new one yet
(PARTICIPANT_JOINED come, before CONFERENCE_JOINED where we adjust the
id). Then comes CONFERENCE_JOINED and we try to update our local id.
We're updating the ID of both ghost and local participant. It could be
also that the delayed CONFERENCE_LEFT comes for the old conference, but
it's too late and it would update the id for both participants.
The approach here reasons that the ID of the local participant
may be reset as soon as the local participant and, respectively, her ID
is no longer involved in a recoverable JitsiConference of interest to
the user and, consequently, the app.
Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
Co-authored-by: Lyubo Marinov <lmarinov@atlassian.com>
2018-05-16 20:08:34 +00:00
|
|
|
/**
|
|
|
|
* Evaluates a specific predicate for each {@link JitsiConference} known to the
|
|
|
|
* redux state features/base/conference while it returns {@code true}.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IStateful} stateful - The redux store, state, or
|
fix(base/participants): ensure default local id outside of conference
Makes sure that whenever a conference is left or switched, the local
participant's id will be equal to the default value.
The problem fixed by this commit is a situation where the local
participant may end up sharing the same ID with it's "ghost" when
rejoining a disconnected conference. The most important and easiest to
hit case is when the conference is left after the CONFERENCE_FAILED
event.
Another rare and harder to encounter in the real world issue is
where CONFERENCE_LEFT may come with the delay due to it's asynchronous
nature. The step by step scenario is as follows: trying to leave a
conference, but the network is not doing well, so it takes time,
requests are timing out. After getting back to the welcome page the
the CONFERENCE_LEFT has not arrived yet. The same conference is joined
again and the load config may timeout, but it will be read from the
cache. Now the network gets better and conference is joining which
results in our ghost participant added to the redux state. At this point
there's the root issue: two participants with the same id, because the
local one was neither cleared nor set to the new one yet
(PARTICIPANT_JOINED come, before CONFERENCE_JOINED where we adjust the
id). Then comes CONFERENCE_JOINED and we try to update our local id.
We're updating the ID of both ghost and local participant. It could be
also that the delayed CONFERENCE_LEFT comes for the old conference, but
it's too late and it would update the id for both participants.
The approach here reasons that the ID of the local participant
may be reset as soon as the local participant and, respectively, her ID
is no longer involved in a recoverable JitsiConference of interest to
the user and, consequently, the app.
Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
Co-authored-by: Lyubo Marinov <lmarinov@atlassian.com>
2018-05-16 20:08:34 +00:00
|
|
|
* {@code getState} function.
|
|
|
|
* @param {Function} predicate - The predicate to evaluate for each
|
|
|
|
* {@code JitsiConference} know to the redux state features/base/conference
|
|
|
|
* while it returns {@code true}.
|
|
|
|
* @returns {boolean} If the specified {@code predicate} returned {@code true}
|
|
|
|
* for all {@code JitsiConference} instances known to the redux state
|
|
|
|
* features/base/conference.
|
|
|
|
*/
|
|
|
|
export function forEachConference(
|
2022-09-19 07:40:03 +00:00
|
|
|
stateful: IStateful,
|
|
|
|
predicate: (a: any, b: URL) => boolean) {
|
2021-04-21 13:48:05 +00:00
|
|
|
const state = getConferenceState(toState(stateful));
|
fix(base/participants): ensure default local id outside of conference
Makes sure that whenever a conference is left or switched, the local
participant's id will be equal to the default value.
The problem fixed by this commit is a situation where the local
participant may end up sharing the same ID with it's "ghost" when
rejoining a disconnected conference. The most important and easiest to
hit case is when the conference is left after the CONFERENCE_FAILED
event.
Another rare and harder to encounter in the real world issue is
where CONFERENCE_LEFT may come with the delay due to it's asynchronous
nature. The step by step scenario is as follows: trying to leave a
conference, but the network is not doing well, so it takes time,
requests are timing out. After getting back to the welcome page the
the CONFERENCE_LEFT has not arrived yet. The same conference is joined
again and the load config may timeout, but it will be read from the
cache. Now the network gets better and conference is joining which
results in our ghost participant added to the redux state. At this point
there's the root issue: two participants with the same id, because the
local one was neither cleared nor set to the new one yet
(PARTICIPANT_JOINED come, before CONFERENCE_JOINED where we adjust the
id). Then comes CONFERENCE_JOINED and we try to update our local id.
We're updating the ID of both ghost and local participant. It could be
also that the delayed CONFERENCE_LEFT comes for the old conference, but
it's too late and it would update the id for both participants.
The approach here reasons that the ID of the local participant
may be reset as soon as the local participant and, respectively, her ID
is no longer involved in a recoverable JitsiConference of interest to
the user and, consequently, the app.
Co-authored-by: Pawel Domas <pawel.domas@jitsi.org>
Co-authored-by: Lyubo Marinov <lmarinov@atlassian.com>
2018-05-16 20:08:34 +00:00
|
|
|
|
|
|
|
for (const v of Object.values(state)) {
|
|
|
|
// Does the value of the base/conference's property look like a
|
|
|
|
// JitsiConference?
|
|
|
|
if (v && typeof v === 'object') {
|
|
|
|
// $FlowFixMe
|
|
|
|
const url: URL = v[JITSI_CONFERENCE_URL_KEY];
|
|
|
|
|
|
|
|
// XXX The Web version of Jitsi Meet does not utilize
|
|
|
|
// JITSI_CONFERENCE_URL_KEY at the time of this writing. An
|
|
|
|
// alternative is necessary then to recognize JitsiConference
|
|
|
|
// instances and myUserId is as good as any other property.
|
|
|
|
if ((url || typeof v.myUserId === 'function')
|
|
|
|
&& !predicate(v, url)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-30 15:43:57 +00:00
|
|
|
/**
|
|
|
|
* Returns the display name of the conference.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IStateful} stateful - Reference that can be resolved to Redux
|
2019-01-30 15:43:57 +00:00
|
|
|
* state with the {@code toState} function.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getConferenceName(stateful: IStateful): string {
|
2019-01-30 15:43:57 +00:00
|
|
|
const state = toState(stateful);
|
|
|
|
const { callee } = state['features/base/jwt'];
|
2019-05-29 07:53:12 +00:00
|
|
|
const { callDisplayName } = state['features/base/config'];
|
2022-10-07 12:14:53 +00:00
|
|
|
const { localSubject, pendingSubjectChange, room, subject } = getConferenceState(state);
|
2019-01-30 15:43:57 +00:00
|
|
|
|
2022-10-07 12:14:53 +00:00
|
|
|
return (pendingSubjectChange
|
|
|
|
|| localSubject
|
2019-07-10 17:27:11 +00:00
|
|
|
|| subject
|
|
|
|
|| callDisplayName
|
2022-09-19 07:40:03 +00:00
|
|
|
|| callee?.name
|
|
|
|
|| (room && safeStartCase(safeDecodeURIComponent(room)))) ?? '';
|
2019-01-30 15:43:57 +00:00
|
|
|
}
|
|
|
|
|
2020-04-25 14:36:14 +00:00
|
|
|
/**
|
2021-03-16 15:59:33 +00:00
|
|
|
* Returns the name of the conference formatted for the title.
|
2020-04-25 14:36:14 +00:00
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IStateful} stateful - Reference that can be resolved to Redux state with the {@code toState}
|
2020-04-25 14:36:14 +00:00
|
|
|
* function.
|
2021-03-16 15:59:33 +00:00
|
|
|
* @returns {string} - The name of the conference formatted for the title.
|
2020-04-25 14:36:14 +00:00
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getConferenceNameForTitle(stateful: IStateful) {
|
|
|
|
return safeStartCase(safeDecodeURIComponent(getConferenceState(toState(stateful)).room ?? ''));
|
2020-04-25 14:36:14 +00:00
|
|
|
}
|
|
|
|
|
2021-08-04 10:56:07 +00:00
|
|
|
/**
|
|
|
|
* Returns an object aggregating the conference options.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IStateful} stateful - The redux store state.
|
2021-08-04 10:56:07 +00:00
|
|
|
* @returns {Object} - Options object.
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getConferenceOptions(stateful: IStateful) {
|
2021-08-04 10:56:07 +00:00
|
|
|
const state = toState(stateful);
|
|
|
|
|
|
|
|
const config = state['features/base/config'];
|
|
|
|
const { locationURL } = state['features/base/connection'];
|
|
|
|
const { tenant } = state['features/base/jwt'];
|
2022-09-19 07:40:03 +00:00
|
|
|
const { email, name: nick } = getLocalParticipant(state) ?? {};
|
|
|
|
const options: any = { ...config };
|
2021-08-04 10:56:07 +00:00
|
|
|
|
|
|
|
if (tenant) {
|
|
|
|
options.siteID = tenant;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.enableDisplayNameInStats && nick) {
|
|
|
|
options.statisticsDisplayName = nick;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.enableEmailInStats && email) {
|
|
|
|
options.statisticsId = email;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (locationURL) {
|
|
|
|
options.confID = `${locationURL.host}${getBackendSafePath(locationURL.pathname)}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
options.applicationName = getName();
|
2021-08-09 09:29:50 +00:00
|
|
|
options.transcriptionLanguage = determineTranscriptionLanguage(options);
|
2021-08-04 10:56:07 +00:00
|
|
|
|
2021-08-17 17:24:18 +00:00
|
|
|
// Disable analytics, if requested.
|
2021-08-04 10:56:07 +00:00
|
|
|
if (options.disableThirdPartyRequests) {
|
2021-08-17 17:24:18 +00:00
|
|
|
delete config.analytics?.scriptURLs;
|
|
|
|
delete config.analytics?.amplitudeAPPKey;
|
|
|
|
delete config.analytics?.googleAnalyticsTrackingId;
|
2021-08-04 10:56:07 +00:00
|
|
|
delete options.callStatsID;
|
|
|
|
delete options.callStatsSecret;
|
|
|
|
} else {
|
|
|
|
options.getWiFiStatsMethod = getWiFiStatsMethod;
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
2020-01-13 17:12:25 +00:00
|
|
|
/**
|
|
|
|
* Returns the UTC timestamp when the first participant joined the conference.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IStateful} stateful - Reference that can be resolved to Redux
|
2020-01-13 17:12:25 +00:00
|
|
|
* state with the {@code toState} function.
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getConferenceTimestamp(stateful: IStateful) {
|
2020-01-13 17:12:25 +00:00
|
|
|
const state = toState(stateful);
|
2021-04-21 13:48:05 +00:00
|
|
|
const { conferenceTimestamp } = getConferenceState(state);
|
2020-01-13 17:12:25 +00:00
|
|
|
|
|
|
|
return conferenceTimestamp;
|
|
|
|
}
|
|
|
|
|
2017-09-28 21:25:04 +00:00
|
|
|
/**
|
|
|
|
* Returns the current {@code JitsiConference} which is joining or joined and is
|
|
|
|
* not leaving. Please note the contrast with merely reading the
|
|
|
|
* {@code conference} state of the feature base/conference which is not joining
|
|
|
|
* but may be leaving already.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IStateful} stateful - The redux store, state, or
|
2017-09-28 21:25:04 +00:00
|
|
|
* {@code getState} function.
|
|
|
|
* @returns {JitsiConference|undefined}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getCurrentConference(stateful: IStateful): any {
|
2020-04-15 13:13:43 +00:00
|
|
|
const { conference, joining, leaving, membersOnly, passwordRequired }
|
2021-04-21 13:48:05 +00:00
|
|
|
= getConferenceState(toState(stateful));
|
2017-09-28 21:25:04 +00:00
|
|
|
|
2021-03-16 15:59:33 +00:00
|
|
|
// There is a precedence
|
2019-11-20 10:57:18 +00:00
|
|
|
if (conference) {
|
|
|
|
return conference === leaving ? undefined : conference;
|
|
|
|
}
|
|
|
|
|
2020-04-15 13:13:43 +00:00
|
|
|
return joining || passwordRequired || membersOnly;
|
2017-09-28 21:25:04 +00:00
|
|
|
}
|
|
|
|
|
2020-04-16 10:47:10 +00:00
|
|
|
/**
|
|
|
|
* Returns the stored room name.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IState} state - The current state of the app.
|
2020-04-16 10:47:10 +00:00
|
|
|
* @returns {string}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getRoomName(state: IState) {
|
2021-04-21 13:48:05 +00:00
|
|
|
return getConferenceState(state).room;
|
2020-04-16 10:47:10 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 06:53:07 +00:00
|
|
|
/**
|
|
|
|
* Get an obfuscated room name or create and persist it if it doesn't exists.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IState} state - The current state of the app.
|
2022-06-21 06:53:07 +00:00
|
|
|
* @param {Function} dispatch - The Redux dispatch function.
|
|
|
|
* @returns {string} - Obfuscated room name.
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getOrCreateObfuscatedRoomName(state: IState, dispatch: IStore['dispatch']) {
|
2022-06-21 06:53:07 +00:00
|
|
|
let { obfuscatedRoom } = getConferenceState(state);
|
|
|
|
const { obfuscatedRoomSource } = getConferenceState(state);
|
|
|
|
const room = getRoomName(state);
|
|
|
|
|
2022-09-19 07:40:03 +00:00
|
|
|
if (!room) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-21 06:53:07 +00:00
|
|
|
// On native mobile the store doesn't clear when joining a new conference so we might have the obfuscatedRoom
|
|
|
|
// stored even though a different room was joined.
|
|
|
|
// Check if the obfuscatedRoom was already computed for the current room.
|
|
|
|
if (!obfuscatedRoom || (obfuscatedRoomSource !== room)) {
|
|
|
|
obfuscatedRoom = sha512(room);
|
|
|
|
dispatch(setObfuscatedRoom(obfuscatedRoom, room));
|
|
|
|
}
|
|
|
|
|
|
|
|
return obfuscatedRoom;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Analytics may require an obfuscated room name, this functions decides based on a config if the normal or
|
|
|
|
* obfuscated room name should be returned.
|
|
|
|
*
|
2022-09-19 07:40:03 +00:00
|
|
|
* @param {IState} state - The current state of the app.
|
2022-06-21 06:53:07 +00:00
|
|
|
* @param {Function} dispatch - The Redux dispatch function.
|
|
|
|
* @returns {string} - Analytics room name.
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function getAnalyticsRoomName(state: IState, dispatch: IStore['dispatch']) {
|
2022-06-21 06:53:07 +00:00
|
|
|
const { analysis: { obfuscateRoomName = false } = {} } = state['features/base/config'];
|
|
|
|
|
|
|
|
if (obfuscateRoomName) {
|
|
|
|
return getOrCreateObfuscatedRoomName(state, dispatch);
|
|
|
|
}
|
|
|
|
|
|
|
|
return getRoomName(state);
|
|
|
|
}
|
|
|
|
|
2021-08-04 10:56:07 +00:00
|
|
|
/**
|
|
|
|
* Returns the result of getWiFiStats from the global NS or does nothing
|
|
|
|
* (returns empty result).
|
|
|
|
* Fixes a concurrency problem where we need to pass a function when creating
|
|
|
|
* a JitsiConference, but that method is added to the context later.
|
|
|
|
*
|
|
|
|
* @returns {Promise}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
function getWiFiStatsMethod() {
|
|
|
|
const gloabalNS = getJitsiMeetGlobalNS();
|
|
|
|
|
|
|
|
return gloabalNS.getWiFiStats ? gloabalNS.getWiFiStats() : Promise.resolve('{}');
|
|
|
|
}
|
|
|
|
|
2016-10-05 14:36:59 +00:00
|
|
|
/**
|
2018-11-08 12:25:02 +00:00
|
|
|
* Handle an error thrown by the backend (i.e. {@code lib-jitsi-meet}) while
|
|
|
|
* manipulating a conference participant (e.g. Pin or select participant).
|
2016-10-05 14:36:59 +00:00
|
|
|
*
|
|
|
|
* @param {Error} err - The Error which was thrown by the backend while
|
|
|
|
* manipulating a conference participant and which is to be handled.
|
2017-09-28 21:25:04 +00:00
|
|
|
* @protected
|
2016-10-05 14:36:59 +00:00
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function _handleParticipantError(err: Error) {
|
2016-10-05 14:36:59 +00:00
|
|
|
// XXX DataChannels are initialized at some later point when the conference
|
|
|
|
// has multiple participants, but code that pins or selects a participant
|
|
|
|
// might be executed before. So here we're swallowing a particular error.
|
|
|
|
// TODO Lib-jitsi-meet should be fixed to not throw such an exception in
|
|
|
|
// these scenarios.
|
|
|
|
if (err.message !== 'Data channels support is disabled!') {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines whether a specific string is a valid room name.
|
|
|
|
*
|
|
|
|
* @param {(string|undefined)} room - The name of the conference room to check
|
|
|
|
* for validity.
|
|
|
|
* @returns {boolean} If the specified room name is valid, then true; otherwise,
|
|
|
|
* false.
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
export function isRoomValid(room?: string) {
|
2016-10-05 14:36:59 +00:00
|
|
|
return typeof room === 'string' && room !== '';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a set of local tracks from a conference.
|
|
|
|
*
|
|
|
|
* @param {JitsiConference} conference - Conference instance.
|
|
|
|
* @param {JitsiLocalTrack[]} localTracks - List of local media tracks.
|
2017-09-28 21:25:04 +00:00
|
|
|
* @protected
|
2016-10-05 14:36:59 +00:00
|
|
|
* @returns {Promise}
|
|
|
|
*/
|
2017-10-13 19:31:05 +00:00
|
|
|
export function _removeLocalTracksFromConference(
|
2022-09-19 07:40:03 +00:00
|
|
|
conference: IJitsiConference,
|
2017-10-13 19:31:05 +00:00
|
|
|
localTracks: Array<Object>) {
|
2016-10-05 14:36:59 +00:00
|
|
|
return Promise.all(localTracks.map(track =>
|
|
|
|
conference.removeTrack(track)
|
2022-09-19 07:40:03 +00:00
|
|
|
.catch((err: Error) => {
|
2016-10-05 14:36:59 +00:00
|
|
|
// Local track might be already disposed by direct
|
|
|
|
// JitsiTrack#dispose() call. So we should ignore this error
|
|
|
|
// here.
|
|
|
|
if (err.name !== JitsiTrackErrors.TRACK_IS_DISPOSED) {
|
|
|
|
_reportError(
|
|
|
|
'Failed to remove local track from conference',
|
|
|
|
err);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reports a specific Error with a specific error message. While the
|
|
|
|
* implementation merely logs the specified msg and err via the console at the
|
|
|
|
* time of this writing, the intention of the function is to abstract the
|
|
|
|
* reporting of errors and facilitate elaborating on it in the future.
|
|
|
|
*
|
|
|
|
* @param {string} msg - The error message to report.
|
|
|
|
* @param {Error} err - The Error to report.
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-09-19 07:40:03 +00:00
|
|
|
function _reportError(msg: string, err: Error) {
|
2016-10-05 14:36:59 +00:00
|
|
|
// TODO This is a good point to call some global error handler when we have
|
|
|
|
// one.
|
2018-07-30 14:38:25 +00:00
|
|
|
logger.error(msg, err);
|
2016-10-05 14:36:59 +00:00
|
|
|
}
|
2017-10-06 17:52:23 +00:00
|
|
|
|
|
|
|
/**
|
2017-10-13 19:31:05 +00:00
|
|
|
* Sends a representation of the local participant such as her avatar (URL),
|
2021-11-23 11:12:12 +00:00
|
|
|
* email address, and display name to (the remote participants of) a specific
|
2017-10-13 19:31:05 +00:00
|
|
|
* conference.
|
2017-10-06 17:52:23 +00:00
|
|
|
*
|
2017-10-13 19:31:05 +00:00
|
|
|
* @param {Function|Object} stateful - The redux store, state, or
|
|
|
|
* {@code getState} function.
|
|
|
|
* @param {JitsiConference} conference - The {@code JitsiConference} to which
|
|
|
|
* the representation of the local participant is to be sent.
|
2017-10-06 17:52:23 +00:00
|
|
|
* @returns {void}
|
|
|
|
*/
|
2017-10-13 19:31:05 +00:00
|
|
|
export function sendLocalParticipant(
|
2022-09-19 07:40:03 +00:00
|
|
|
stateful: IStateful,
|
|
|
|
conference: IJitsiConference) {
|
2018-06-15 18:10:22 +00:00
|
|
|
const {
|
|
|
|
avatarURL,
|
|
|
|
email,
|
|
|
|
features,
|
|
|
|
name
|
2022-09-19 07:40:03 +00:00
|
|
|
} = getLocalParticipant(stateful) ?? {};
|
2017-10-06 17:52:23 +00:00
|
|
|
|
|
|
|
avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
|
|
|
|
value: avatarURL
|
|
|
|
});
|
|
|
|
email && conference.sendCommand(EMAIL_COMMAND, {
|
|
|
|
value: email
|
|
|
|
});
|
2018-06-15 18:10:22 +00:00
|
|
|
|
|
|
|
if (features && features['screen-sharing'] === 'true') {
|
|
|
|
conference.setLocalParticipantProperty('features_screen-sharing', true);
|
|
|
|
}
|
|
|
|
|
2017-10-06 17:52:23 +00:00
|
|
|
conference.setDisplayName(name);
|
|
|
|
}
|
2020-03-25 11:35:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A safe implementation of lodash#startCase that doesn't deburr the string.
|
|
|
|
*
|
|
|
|
* NOTE: According to lodash roadmap, lodash v5 will have this function.
|
|
|
|
*
|
|
|
|
* Code based on https://github.com/lodash/lodash/blob/master/startCase.js.
|
|
|
|
*
|
|
|
|
* @param {string} s - The string to do start case on.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function safeStartCase(s = '') {
|
|
|
|
return _.words(`${s}`.replace(/['\u2019]/g, '')).reduce(
|
|
|
|
(result, word, index) => result + (index ? ' ' : '') + _.upperFirst(word)
|
|
|
|
, '');
|
|
|
|
}
|