2020-03-05 02:34:10 +08:00
|
|
|
import React, { Component, Fragment } from 'react';
|
2018-01-08 12:44:42 +08:00
|
|
|
import { withTracker } from 'meteor/react-meteor-data';
|
2017-06-06 20:33:53 +08:00
|
|
|
import PropTypes from 'prop-types';
|
2017-03-11 02:33:46 +08:00
|
|
|
import Auth from '/imports/ui/services/auth';
|
|
|
|
import AppContainer from '/imports/ui/components/app/container';
|
2017-03-11 04:47:23 +08:00
|
|
|
import ErrorScreen from '/imports/ui/components/error-screen/component';
|
2017-12-15 03:03:34 +08:00
|
|
|
import MeetingEnded from '/imports/ui/components/meeting-ended/component';
|
2017-03-11 02:33:46 +08:00
|
|
|
import LoadingScreen from '/imports/ui/components/loading-screen/component';
|
2017-04-06 20:36:59 +08:00
|
|
|
import Settings from '/imports/ui/services/settings';
|
2018-07-12 06:03:56 +08:00
|
|
|
import logger from '/imports/startup/client/logger';
|
2018-07-19 20:46:44 +08:00
|
|
|
import Users from '/imports/api/users';
|
2018-10-13 01:05:30 +08:00
|
|
|
import { Session } from 'meteor/session';
|
2020-01-17 21:20:03 +08:00
|
|
|
import { FormattedMessage } from 'react-intl';
|
2019-08-22 03:27:15 +08:00
|
|
|
import Meetings, { RecordMeetings } from '../../api/meetings';
|
2019-03-20 04:06:13 +08:00
|
|
|
import AppService from '/imports/ui/components/app/service';
|
2019-04-10 01:55:10 +08:00
|
|
|
import Breakouts from '/imports/api/breakouts';
|
|
|
|
import AudioService from '/imports/ui/components/audio/service';
|
|
|
|
import { notify } from '/imports/ui/services/notification';
|
2020-01-30 05:40:00 +08:00
|
|
|
import deviceInfo from '/imports/utils/deviceInfo';
|
2020-03-03 04:49:15 +08:00
|
|
|
import { invalidateCookie } from '/imports/ui/components/audio/audio-modal/service';
|
2020-01-30 05:40:00 +08:00
|
|
|
import getFromUserSettings from '/imports/ui/services/users-settings';
|
2020-03-05 02:34:10 +08:00
|
|
|
import LayoutManager from '/imports/ui/components/layout/layout-manager';
|
2020-03-25 20:52:23 +08:00
|
|
|
import { withLayoutContext } from '/imports/ui/components/layout/context';
|
2020-04-23 22:07:44 +08:00
|
|
|
import VideoService from '/imports/ui/components/video-provider/service';
|
2020-09-04 07:35:57 +08:00
|
|
|
import DebugWindow from '/imports/ui/components/debug-window/component'
|
2020-12-01 00:09:35 +08:00
|
|
|
import {Meteor} from "meteor/meteor";
|
2020-01-30 05:40:00 +08:00
|
|
|
|
2020-03-06 07:14:22 +08:00
|
|
|
const CHAT_CONFIG = Meteor.settings.public.chat;
|
|
|
|
const CHAT_ENABLED = CHAT_CONFIG.enabled;
|
|
|
|
const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id;
|
2019-01-22 03:28:37 +08:00
|
|
|
|
2019-09-19 04:06:59 +08:00
|
|
|
const BREAKOUT_END_NOTIFY_DELAY = 50;
|
|
|
|
|
2019-04-11 23:04:10 +08:00
|
|
|
const HTML = document.getElementsByTagName('html')[0];
|
2018-08-06 20:05:07 +08:00
|
|
|
|
2019-04-10 01:55:10 +08:00
|
|
|
let breakoutNotified = false;
|
2018-08-06 20:05:07 +08:00
|
|
|
|
2017-06-06 20:33:53 +08:00
|
|
|
const propTypes = {
|
2019-04-23 22:22:11 +08:00
|
|
|
subscriptionsReady: PropTypes.bool,
|
2018-08-11 01:51:12 +08:00
|
|
|
approved: PropTypes.bool,
|
2019-04-06 02:10:05 +08:00
|
|
|
meetingHasEnded: PropTypes.bool.isRequired,
|
2019-02-07 18:56:29 +08:00
|
|
|
meetingExist: PropTypes.bool,
|
2017-06-06 20:33:53 +08:00
|
|
|
};
|
2017-03-11 02:33:46 +08:00
|
|
|
|
2017-06-06 20:33:53 +08:00
|
|
|
const defaultProps = {
|
2019-06-05 03:23:44 +08:00
|
|
|
approved: false,
|
2019-02-07 18:56:29 +08:00
|
|
|
meetingExist: false,
|
2019-04-23 22:22:11 +08:00
|
|
|
subscriptionsReady: false,
|
2017-06-06 20:33:53 +08:00
|
|
|
};
|
2017-03-11 02:33:46 +08:00
|
|
|
|
2019-03-12 21:56:05 +08:00
|
|
|
const fullscreenChangedEvents = [
|
|
|
|
'fullscreenchange',
|
|
|
|
'webkitfullscreenchange',
|
|
|
|
'mozfullscreenchange',
|
|
|
|
'MSFullscreenChange',
|
|
|
|
];
|
|
|
|
|
2017-03-11 02:33:46 +08:00
|
|
|
class Base extends Component {
|
2019-03-12 00:21:12 +08:00
|
|
|
static handleFullscreenChange() {
|
|
|
|
if (document.fullscreenElement
|
|
|
|
|| document.webkitFullscreenElement
|
|
|
|
|| document.mozFullScreenElement
|
|
|
|
|| document.msFullscreenElement) {
|
2019-03-13 01:05:32 +08:00
|
|
|
Session.set('isFullscreen', true);
|
2019-03-12 00:21:12 +08:00
|
|
|
} else {
|
2019-03-13 01:05:32 +08:00
|
|
|
Session.set('isFullscreen', false);
|
2019-03-12 00:21:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 02:33:46 +08:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
loading: false,
|
2019-01-22 03:28:37 +08:00
|
|
|
meetingExisted: false,
|
2017-03-11 02:33:46 +08:00
|
|
|
};
|
|
|
|
this.updateLoadingState = this.updateLoadingState.bind(this);
|
|
|
|
}
|
|
|
|
|
2019-03-12 00:21:12 +08:00
|
|
|
componentDidMount() {
|
2019-04-11 23:04:10 +08:00
|
|
|
const { animations } = this.props;
|
|
|
|
|
|
|
|
if (animations) HTML.classList.add('animationsEnabled');
|
|
|
|
if (!animations) HTML.classList.add('animationsDisabled');
|
|
|
|
|
2019-03-12 00:21:12 +08:00
|
|
|
fullscreenChangedEvents.forEach((event) => {
|
|
|
|
document.addEventListener(event, Base.handleFullscreenChange);
|
|
|
|
});
|
2019-03-13 01:05:32 +08:00
|
|
|
Session.set('isFullscreen', false);
|
2019-03-12 00:21:12 +08:00
|
|
|
}
|
|
|
|
|
2019-02-07 18:56:29 +08:00
|
|
|
componentDidUpdate(prevProps, prevState) {
|
2019-01-22 03:28:37 +08:00
|
|
|
const {
|
|
|
|
approved,
|
|
|
|
meetingExist,
|
2019-02-01 20:59:52 +08:00
|
|
|
animations,
|
2019-04-12 05:12:54 +08:00
|
|
|
ejected,
|
2019-06-27 00:29:34 +08:00
|
|
|
isMeteorConnected,
|
2019-03-11 20:56:41 +08:00
|
|
|
subscriptionsReady,
|
2020-03-03 04:49:15 +08:00
|
|
|
meetingIsBreakout,
|
2020-06-09 11:09:46 +08:00
|
|
|
layoutContextDispatch,
|
|
|
|
usersVideo,
|
2019-01-22 03:28:37 +08:00
|
|
|
} = this.props;
|
2019-03-12 00:21:12 +08:00
|
|
|
const {
|
|
|
|
loading,
|
|
|
|
meetingExisted,
|
|
|
|
} = this.state;
|
2018-07-19 20:46:44 +08:00
|
|
|
|
2020-03-03 04:49:15 +08:00
|
|
|
if (prevProps.meetingIsBreakout === undefined && !meetingIsBreakout) {
|
|
|
|
invalidateCookie('joinedAudio');
|
|
|
|
}
|
|
|
|
|
2020-06-09 11:09:46 +08:00
|
|
|
if (usersVideo !== prevProps.usersVideo) {
|
|
|
|
layoutContextDispatch(
|
|
|
|
{
|
|
|
|
type: 'setUsersVideo',
|
|
|
|
value: usersVideo.length,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-03-11 20:56:41 +08:00
|
|
|
if (!prevProps.subscriptionsReady && subscriptionsReady) {
|
|
|
|
logger.info({ logCode: 'startup_client_subscriptions_ready' }, 'Subscriptions are ready');
|
|
|
|
}
|
|
|
|
|
2019-03-20 04:06:13 +08:00
|
|
|
if (prevProps.meetingExist && !meetingExist && !meetingExisted) {
|
|
|
|
this.setMeetingExisted(true);
|
2019-01-18 02:31:04 +08:00
|
|
|
}
|
|
|
|
|
2019-03-20 04:06:13 +08:00
|
|
|
// In case the meteor restart avoid error log
|
2019-06-27 00:29:34 +08:00
|
|
|
if (isMeteorConnected && (prevState.meetingExisted !== meetingExisted) && meetingExisted) {
|
2019-03-20 04:06:13 +08:00
|
|
|
this.setMeetingExisted(false);
|
2019-01-22 03:28:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// In case the meeting delayed to load
|
2019-04-06 02:10:05 +08:00
|
|
|
if (!subscriptionsReady || !meetingExist) return;
|
2019-01-18 02:31:04 +08:00
|
|
|
|
2019-04-25 04:48:16 +08:00
|
|
|
if (approved && loading && subscriptionsReady) this.updateLoadingState(false);
|
2019-01-03 01:31:57 +08:00
|
|
|
|
|
|
|
if (prevProps.ejected || ejected) {
|
|
|
|
Session.set('codeError', '403');
|
|
|
|
Session.set('isMeetingEnded', true);
|
|
|
|
}
|
2019-01-25 00:16:23 +08:00
|
|
|
|
2019-02-07 18:56:29 +08:00
|
|
|
// In case the meteor restart avoid error log
|
2019-06-27 00:29:34 +08:00
|
|
|
if (isMeteorConnected && (prevState.meetingExisted !== meetingExisted)) {
|
2019-02-07 18:56:29 +08:00
|
|
|
this.setMeetingExisted(false);
|
|
|
|
}
|
|
|
|
|
2019-04-11 23:04:10 +08:00
|
|
|
const enabled = HTML.classList.contains('animationsEnabled');
|
|
|
|
const disabled = HTML.classList.contains('animationsDisabled');
|
|
|
|
|
2019-01-25 00:16:23 +08:00
|
|
|
if (animations && animations !== prevProps.animations) {
|
2019-04-11 23:04:10 +08:00
|
|
|
if (disabled) HTML.classList.remove('animationsDisabled');
|
|
|
|
HTML.classList.add('animationsEnabled');
|
2019-01-25 00:16:23 +08:00
|
|
|
} else if (!animations && animations !== prevProps.animations) {
|
2019-04-11 23:04:10 +08:00
|
|
|
if (enabled) HTML.classList.remove('animationsEnabled');
|
|
|
|
HTML.classList.add('animationsDisabled');
|
2019-01-25 00:16:23 +08:00
|
|
|
}
|
2018-07-19 20:46:44 +08:00
|
|
|
}
|
|
|
|
|
2019-03-12 00:21:12 +08:00
|
|
|
componentWillUnmount() {
|
|
|
|
fullscreenChangedEvents.forEach((event) => {
|
|
|
|
document.removeEventListener(event, Base.handleFullscreenChange);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-01-22 03:28:37 +08:00
|
|
|
setMeetingExisted(meetingExisted) {
|
|
|
|
this.setState({ meetingExisted });
|
|
|
|
}
|
|
|
|
|
2017-03-11 02:33:46 +08:00
|
|
|
updateLoadingState(loading = false) {
|
|
|
|
this.setState({
|
|
|
|
loading,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
renderByState() {
|
2018-10-13 01:05:30 +08:00
|
|
|
const { updateLoadingState } = this;
|
|
|
|
const stateControls = { updateLoadingState };
|
2019-04-06 02:10:05 +08:00
|
|
|
const { loading } = this.state;
|
2019-01-22 03:28:37 +08:00
|
|
|
const {
|
2020-06-03 03:47:26 +08:00
|
|
|
codeError,
|
2019-03-20 04:06:13 +08:00
|
|
|
ejected,
|
2020-08-03 20:44:21 +08:00
|
|
|
ejectedReason,
|
2019-01-22 03:28:37 +08:00
|
|
|
meetingExist,
|
2019-04-06 02:10:05 +08:00
|
|
|
meetingHasEnded,
|
|
|
|
meetingIsBreakout,
|
2019-04-25 04:48:16 +08:00
|
|
|
subscriptionsReady,
|
2019-05-18 03:39:05 +08:00
|
|
|
User,
|
2019-01-22 03:28:37 +08:00
|
|
|
} = this.props;
|
|
|
|
|
2019-04-27 00:01:58 +08:00
|
|
|
if ((loading || !subscriptionsReady) && !meetingHasEnded && meetingExist) {
|
2019-04-06 02:10:05 +08:00
|
|
|
return (<LoadingScreen>{loading}</LoadingScreen>);
|
|
|
|
}
|
2019-01-22 03:28:37 +08:00
|
|
|
|
2020-01-10 07:50:10 +08:00
|
|
|
if (ejected) {
|
2020-08-03 20:44:21 +08:00
|
|
|
return (<MeetingEnded code="403" reason={ejectedReason} />);
|
2019-03-13 02:02:52 +08:00
|
|
|
}
|
|
|
|
|
2020-08-03 20:44:21 +08:00
|
|
|
if ((meetingHasEnded || User?.loggedOut) && meetingIsBreakout) {
|
2020-05-27 00:41:22 +08:00
|
|
|
window.close();
|
|
|
|
return null;
|
|
|
|
}
|
2019-03-20 04:06:13 +08:00
|
|
|
|
2020-08-03 20:44:21 +08:00
|
|
|
if (((meetingHasEnded && !meetingIsBreakout)) || (codeError && User?.loggedOut)) {
|
2019-03-20 04:06:13 +08:00
|
|
|
return (<MeetingEnded code={codeError} />);
|
2018-10-13 01:05:30 +08:00
|
|
|
}
|
|
|
|
|
2019-04-27 00:01:58 +08:00
|
|
|
if (codeError && !meetingHasEnded) {
|
2019-05-25 06:56:17 +08:00
|
|
|
// 680 is set for the codeError when the user requests a logout
|
|
|
|
if (codeError !== '680') {
|
2020-06-03 03:47:26 +08:00
|
|
|
return (<ErrorScreen code={codeError} />);
|
2019-05-25 06:56:17 +08:00
|
|
|
}
|
2020-06-03 03:47:26 +08:00
|
|
|
return (<MeetingEnded code={codeError} />);
|
2019-04-27 00:01:58 +08:00
|
|
|
}
|
2020-08-03 20:44:21 +08:00
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
return (<AppContainer {...this.props} baseControls={stateControls} />);
|
2017-03-11 02:33:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2020-03-25 20:52:23 +08:00
|
|
|
const {
|
|
|
|
meetingExist,
|
|
|
|
} = this.props;
|
2019-04-27 00:01:58 +08:00
|
|
|
const { meetingExisted } = this.state;
|
2017-03-11 02:33:46 +08:00
|
|
|
|
|
|
|
return (
|
2020-03-25 20:52:23 +08:00
|
|
|
<Fragment>
|
2020-09-04 07:35:57 +08:00
|
|
|
{meetingExist && Auth.loggedIn && <DebugWindow />}
|
|
|
|
{meetingExist && Auth.loggedIn && <LayoutManager />}
|
2020-03-25 20:52:23 +08:00
|
|
|
{
|
|
|
|
(!meetingExisted && !meetingExist && Auth.loggedIn)
|
|
|
|
? <LoadingScreen />
|
2020-07-24 05:14:31 +08:00
|
|
|
: this.renderByState()
|
2020-03-25 20:52:23 +08:00
|
|
|
}
|
|
|
|
</Fragment>
|
2017-03-11 02:33:46 +08:00
|
|
|
);
|
|
|
|
}
|
2017-06-03 03:25:02 +08:00
|
|
|
}
|
2017-03-11 02:33:46 +08:00
|
|
|
|
2017-06-06 20:33:53 +08:00
|
|
|
Base.propTypes = propTypes;
|
|
|
|
Base.defaultProps = defaultProps;
|
|
|
|
|
2018-10-03 03:53:13 +08:00
|
|
|
const BaseContainer = withTracker(() => {
|
2019-11-14 06:36:23 +08:00
|
|
|
const {
|
|
|
|
animations,
|
|
|
|
userJoinAudioAlerts,
|
|
|
|
userJoinPushAlerts,
|
|
|
|
} = Settings.application;
|
|
|
|
|
|
|
|
const {
|
|
|
|
credentials,
|
|
|
|
loggedIn,
|
|
|
|
userID: localUserId,
|
|
|
|
} = Auth;
|
|
|
|
|
2019-04-25 04:48:16 +08:00
|
|
|
const { meetingId } = credentials;
|
2018-11-22 00:27:01 +08:00
|
|
|
let breakoutRoomSubscriptionHandler;
|
2019-03-08 00:33:34 +08:00
|
|
|
let meetingModeratorSubscriptionHandler;
|
2019-03-20 04:06:13 +08:00
|
|
|
|
2019-07-25 02:57:39 +08:00
|
|
|
const fields = {
|
2019-07-25 01:59:04 +08:00
|
|
|
approved: 1,
|
|
|
|
authed: 1,
|
|
|
|
ejected: 1,
|
2020-08-03 20:44:21 +08:00
|
|
|
ejectedReason: 1,
|
2019-07-25 01:59:04 +08:00
|
|
|
color: 1,
|
|
|
|
effectiveConnectionType: 1,
|
|
|
|
extId: 1,
|
|
|
|
guest: 1,
|
|
|
|
intId: 1,
|
|
|
|
locked: 1,
|
|
|
|
loggedOut: 1,
|
|
|
|
meetingId: 1,
|
|
|
|
userId: 1,
|
2020-08-03 20:44:21 +08:00
|
|
|
inactivityCheck: 1,
|
|
|
|
responseDelay: 1,
|
2019-07-25 01:59:04 +08:00
|
|
|
};
|
2019-07-25 02:57:39 +08:00
|
|
|
const User = Users.findOne({ intId: credentials.requesterUserId }, { fields });
|
|
|
|
const meeting = Meetings.findOne({ meetingId }, {
|
|
|
|
fields: {
|
|
|
|
meetingEnded: 1,
|
2019-09-19 04:06:59 +08:00
|
|
|
meetingProp: 1,
|
2019-07-25 02:57:39 +08:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
if (meeting && meeting.meetingEnded) {
|
|
|
|
Session.set('codeError', '410');
|
2019-03-20 04:06:13 +08:00
|
|
|
}
|
|
|
|
|
2020-08-06 01:16:41 +08:00
|
|
|
const approved = User?.approved && User?.guest;
|
|
|
|
const ejected = User?.ejected;
|
2020-08-03 20:44:21 +08:00
|
|
|
const ejectedReason = User?.ejectedReason;
|
|
|
|
|
2019-02-08 03:40:27 +08:00
|
|
|
let userSubscriptionHandler;
|
2018-01-11 19:19:56 +08:00
|
|
|
|
2019-09-19 04:06:59 +08:00
|
|
|
Breakouts.find({}, { fields: { _id: 1 } }).observeChanges({
|
2019-04-10 01:55:10 +08:00
|
|
|
added() {
|
|
|
|
breakoutNotified = false;
|
|
|
|
},
|
|
|
|
removed() {
|
2019-09-19 04:06:59 +08:00
|
|
|
// Need to check the number of breakouts left because if a user's role changes to viewer
|
|
|
|
// then all but one room is removed. The data here isn't reactive so no need to filter
|
|
|
|
// the fields
|
|
|
|
const numBreakouts = Breakouts.find().count();
|
|
|
|
if (!AudioService.isUsingAudio() && !breakoutNotified && numBreakouts === 0) {
|
|
|
|
if (meeting && !meeting.meetingEnded && !meeting.meetingProp.isBreakout) {
|
|
|
|
// There's a race condition when reloading a tab where the collection gets cleared
|
|
|
|
// out and then refilled. The removal of the old data triggers the notification so
|
|
|
|
// instead wait a bit and check to see that records weren't added right after.
|
|
|
|
setTimeout(() => {
|
|
|
|
if (breakoutNotified) {
|
|
|
|
notify(
|
|
|
|
<FormattedMessage
|
|
|
|
id="app.toast.breakoutRoomEnded"
|
|
|
|
description="message when the breakout room is ended"
|
|
|
|
/>,
|
|
|
|
'info',
|
|
|
|
'rooms',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}, BREAKOUT_END_NOTIFY_DELAY);
|
2019-04-10 01:55:10 +08:00
|
|
|
}
|
|
|
|
breakoutNotified = true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2019-08-22 03:27:15 +08:00
|
|
|
RecordMeetings.find({ meetingId }, { fields: { recording: 1 } }).observe({
|
2019-04-10 01:55:10 +08:00
|
|
|
changed: (newDocument, oldDocument) => {
|
2019-08-22 03:27:15 +08:00
|
|
|
if (newDocument) {
|
|
|
|
if (!oldDocument.recording && newDocument.recording) {
|
2019-04-11 02:20:31 +08:00
|
|
|
notify(
|
|
|
|
<FormattedMessage
|
|
|
|
id="app.notification.recordingStart"
|
|
|
|
description="Notification for when the recording starts"
|
|
|
|
/>,
|
|
|
|
'success',
|
|
|
|
'record',
|
|
|
|
);
|
|
|
|
}
|
2019-04-10 01:55:10 +08:00
|
|
|
|
2019-08-22 03:27:15 +08:00
|
|
|
if (oldDocument.recording && !newDocument.recording) {
|
2019-04-11 02:20:31 +08:00
|
|
|
notify(
|
|
|
|
<FormattedMessage
|
2019-06-10 22:36:33 +08:00
|
|
|
id="app.notification.recordingPaused"
|
2019-04-11 02:20:31 +08:00
|
|
|
description="Notification for when the recording stops"
|
|
|
|
/>,
|
|
|
|
'error',
|
|
|
|
'record',
|
|
|
|
);
|
|
|
|
}
|
2019-04-10 01:55:10 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2019-11-14 06:36:23 +08:00
|
|
|
if (userJoinAudioAlerts || userJoinPushAlerts) {
|
|
|
|
Users.find({}, { fields: { validated: 1, name: 1, userId: 1 } }).observe({
|
|
|
|
changed: (newDocument) => {
|
|
|
|
if (newDocument.validated && newDocument.name && newDocument.userId !== localUserId) {
|
|
|
|
if (userJoinAudioAlerts) {
|
Correctly set audio input/output devices
When refusing ("thumbs down" button) echo test, user is able to select a different input device. This should work fine for chrome, firefox and safari (once user grants permission when asked by html5client).
For output devices, we depend on setSinkId function, which is enabled by default on current chrome release (2020) but not in Firefox (user needs to enable "setSinkId in about:config page). This implementation is listed as (?) in MDN.
In other words, output device selection should work out of the box for chrome, only.
When selecting an outputDevice, all alert sounds (hangup, screenshare , polling, etc) also goes to the same output device.
This solves #10592
2020-10-07 07:37:55 +08:00
|
|
|
AudioService.playAlertSound(`${Meteor.settings.public.app.cdn
|
2020-12-01 00:09:35 +08:00
|
|
|
+ Meteor.settings.public.app.basename
|
|
|
|
+ Meteor.settings.public.app.instanceId}`
|
Correctly set audio input/output devices
When refusing ("thumbs down" button) echo test, user is able to select a different input device. This should work fine for chrome, firefox and safari (once user grants permission when asked by html5client).
For output devices, we depend on setSinkId function, which is enabled by default on current chrome release (2020) but not in Firefox (user needs to enable "setSinkId in about:config page). This implementation is listed as (?) in MDN.
In other words, output device selection should work out of the box for chrome, only.
When selecting an outputDevice, all alert sounds (hangup, screenshare , polling, etc) also goes to the same output device.
This solves #10592
2020-10-07 07:37:55 +08:00
|
|
|
+ '/resources/sounds/userJoin.mp3');
|
2019-11-14 06:36:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (userJoinPushAlerts) {
|
|
|
|
notify(
|
|
|
|
<FormattedMessage
|
|
|
|
id="app.notification.userJoinPushAlert"
|
|
|
|
description="Notification for a user joins the meeting"
|
|
|
|
values={{
|
|
|
|
0: newDocument.name,
|
|
|
|
}}
|
|
|
|
/>,
|
|
|
|
'info',
|
|
|
|
'user',
|
|
|
|
);
|
|
|
|
}
|
2019-11-13 02:00:48 +08:00
|
|
|
}
|
2019-11-14 06:36:23 +08:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2019-11-06 04:08:26 +08:00
|
|
|
|
2021-02-19 00:11:02 +08:00
|
|
|
if (getFromUserSettings('bbb_show_participants_on_login', Meteor.settings.public.layout.showParticipantsOnLogin) && !deviceInfo.type().isPhone) {
|
2020-05-26 21:07:37 +08:00
|
|
|
if (CHAT_ENABLED && getFromUserSettings('bbb_show_public_chat_on_login', !Meteor.settings.public.chat.startClosed)) {
|
2021-02-19 00:11:02 +08:00
|
|
|
Session.set('openPanel', 'chat');
|
|
|
|
Session.set('idChatOpen', PUBLIC_CHAT_ID);
|
2020-11-28 05:48:02 +08:00
|
|
|
} else {
|
2021-02-19 00:11:02 +08:00
|
|
|
Session.set('openPanel', 'userlist');
|
2020-01-30 05:40:00 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-02-19 00:11:02 +08:00
|
|
|
Session.set('openPanel', '');
|
2020-01-30 05:40:00 +08:00
|
|
|
}
|
2020-03-03 21:59:01 +08:00
|
|
|
|
2020-06-03 03:47:26 +08:00
|
|
|
const codeError = Session.get('codeError');
|
2020-04-23 22:07:44 +08:00
|
|
|
const usersVideo = VideoService.getVideoStreams();
|
2020-04-23 22:07:44 +08:00
|
|
|
|
2017-03-11 02:33:46 +08:00
|
|
|
return {
|
2019-04-24 20:20:38 +08:00
|
|
|
approved,
|
|
|
|
ejected,
|
2020-08-03 20:44:21 +08:00
|
|
|
ejectedReason,
|
2019-02-08 03:40:27 +08:00
|
|
|
userSubscriptionHandler,
|
2018-11-22 00:27:01 +08:00
|
|
|
breakoutRoomSubscriptionHandler,
|
2019-03-08 00:33:34 +08:00
|
|
|
meetingModeratorSubscriptionHandler,
|
2019-01-25 00:16:23 +08:00
|
|
|
animations,
|
2019-01-22 03:28:37 +08:00
|
|
|
User,
|
2019-06-27 00:29:34 +08:00
|
|
|
isMeteorConnected: Meteor.status().connected,
|
2019-04-11 02:20:31 +08:00
|
|
|
meetingExist: !!meeting,
|
2019-04-06 02:10:05 +08:00
|
|
|
meetingHasEnded: !!meeting && meeting.meetingEnded,
|
|
|
|
meetingIsBreakout: AppService.meetingIsBreakout(),
|
2019-04-25 04:48:16 +08:00
|
|
|
subscriptionsReady: Session.get('subscriptionsReady'),
|
2019-04-23 22:22:11 +08:00
|
|
|
loggedIn,
|
2020-06-03 03:47:26 +08:00
|
|
|
codeError,
|
2020-04-23 22:07:44 +08:00
|
|
|
usersVideo,
|
2017-03-11 02:33:46 +08:00
|
|
|
};
|
2020-03-25 20:52:23 +08:00
|
|
|
})(withLayoutContext(Base));
|
2017-06-06 20:33:53 +08:00
|
|
|
|
|
|
|
export default BaseContainer;
|