bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/audio/container.jsx

250 lines
7.8 KiB
React
Raw Normal View History

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { withTracker } from 'meteor/react-meteor-data';
import { Session } from 'meteor/session';
2017-05-02 03:52:57 +08:00
import { withModalMounter } from '/imports/ui/components/modal/service';
import { injectIntl, defineMessages } from 'react-intl';
2018-06-29 02:14:35 +08:00
import _ from 'lodash';
import Breakouts from '/imports/api/breakouts';
import AppService from '/imports/ui/components/app/service';
2018-07-10 03:23:16 +08:00
import { notify } from '/imports/ui/services/notification';
import getFromUserSettings from '/imports/ui/services/users-settings';
import VideoPreviewContainer from '/imports/ui/components/video-preview/container';
2019-05-24 00:47:56 +08:00
import lockContextContainer from '/imports/ui/components/lock-viewers/context/container';
import {
joinMicrophone,
joinListenOnly,
didUserSelectedMicrophone,
didUserSelectedListenOnly,
} from '/imports/ui/components/audio/audio-modal/service';
2017-05-02 03:52:57 +08:00
import Service from './service';
2017-09-29 21:38:10 +08:00
import AudioModalContainer from './audio-modal/container';
import Settings from '/imports/ui/services/settings';
2017-03-28 04:40:44 +08:00
2019-09-05 02:32:58 +08:00
const APP_CONFIG = Meteor.settings.public.app;
const KURENTO_CONFIG = Meteor.settings.public.kurento;
const intlMessages = defineMessages({
joinedAudio: {
id: 'app.audioManager.joinedAudio',
description: 'Joined audio toast message',
},
2017-10-23 20:41:09 +08:00
joinedEcho: {
id: 'app.audioManager.joinedEcho',
description: 'Joined echo test toast message',
},
leftAudio: {
id: 'app.audioManager.leftAudio',
description: 'Left audio toast message',
},
reconnectingAudio: {
id: 'app.audioManager.reconnectingAudio',
description: 'Reconnecting audio toast message',
},
genericError: {
id: 'app.audioManager.genericError',
description: 'Generic error message',
},
connectionError: {
id: 'app.audioManager.connectionError',
description: 'Connection error message',
},
requestTimeout: {
id: 'app.audioManager.requestTimeout',
description: 'Request timeout error message',
},
invalidTarget: {
id: 'app.audioManager.invalidTarget',
description: 'Invalid target error message',
},
2017-10-27 01:14:56 +08:00
mediaError: {
id: 'app.audioManager.mediaError',
description: 'Media error message',
2017-10-27 01:14:56 +08:00
},
2018-06-27 21:56:03 +08:00
BrowserNotSupported: {
id: 'app.audioNotification.audioFailedError1003',
description: 'browser not supported error messsage',
},
2018-07-10 03:23:16 +08:00
reconectingAsListener: {
id: 'app.audioNotificaion.reconnectingAsListenOnly',
description: 'ice negociation error messsage',
},
});
class AudioContainer extends PureComponent {
constructor(props) {
super(props);
this.init = props.init.bind(this);
}
componentDidMount() {
const { meetingIsBreakout } = this.props;
this.init();
if (meetingIsBreakout && !Service.isUsingAudio()) {
this.joinAudio();
}
}
componentDidUpdate(prevProps) {
if (this.userIsReturningFromBreakoutRoom(prevProps)) {
this.joinAudio();
}
}
/**
* Helper function to determine wheter user is returning from breakout room
* to main room.
* @param {[Object} prevProps prevProps param from componentDidUpdate
* @return {boolean} True if user is returning from breakout room
* to main room. False, otherwise.
*/
userIsReturningFromBreakoutRoom(prevProps) {
const { hasBreakoutRooms } = this.props;
const { hasBreakoutRooms: hadBreakoutRooms } = prevProps;
return hadBreakoutRooms && !hasBreakoutRooms;
}
/**
* Helper function that join (or not) user in audio. If user previously
* selected microphone, it will automatically join mic (without audio modal).
* If user previously selected listen only option in audio modal, then it will
* automatically join listen only.
*/
joinAudio() {
if (Service.isConnected()) return;
const {
userSelectedMicrophone,
userSelectedListenOnly,
} = this.props;
if (userSelectedMicrophone) {
joinMicrophone(true);
return;
}
if (userSelectedListenOnly) joinListenOnly();
}
render() {
return null;
}
}
2017-08-15 03:19:35 +08:00
let didMountAutoJoin = false;
2019-09-05 02:32:58 +08:00
const webRtcError = _.range(1001, 1011)
.reduce((acc, value) => ({
...acc,
[value]: { id: `app.audioNotification.audioFailedError${value}` },
}), {});
const messages = {
info: {
JOINED_AUDIO: intlMessages.joinedAudio,
JOINED_ECHO: intlMessages.joinedEcho,
LEFT_AUDIO: intlMessages.leftAudio,
RECONNECTING_AUDIO: intlMessages.reconnectingAudio,
},
error: {
GENERIC_ERROR: intlMessages.genericError,
CONNECTION_ERROR: intlMessages.connectionError,
REQUEST_TIMEOUT: intlMessages.requestTimeout,
INVALID_TARGET: intlMessages.invalidTarget,
MEDIA_ERROR: intlMessages.mediaError,
WEBRTC_NOT_SUPPORTED: intlMessages.BrowserNotSupported,
...webRtcError,
},
};
2019-05-24 00:47:56 +08:00
export default lockContextContainer(withModalMounter(injectIntl(withTracker(({ mountModal, intl, userLocks }) => {
const { microphoneConstraints } = Settings.application;
const autoJoin = getFromUserSettings('bbb_auto_join_audio', APP_CONFIG.autoJoin);
const enableVideo = getFromUserSettings('bbb_enable_video', KURENTO_CONFIG.enableVideo);
const autoShareWebcam = getFromUserSettings('bbb_auto_share_webcam', KURENTO_CONFIG.autoShareWebcam);
2019-06-12 02:04:47 +08:00
const { userWebcam, userMic } = userLocks;
const userSelectedMicrophone = didUserSelectedMicrophone();
const userSelectedListenOnly = didUserSelectedListenOnly();
const meetingIsBreakout = AppService.meetingIsBreakout();
const hasBreakoutRooms = AppService.getBreakoutRooms().length > 0;
2019-05-08 03:49:32 +08:00
const openAudioModal = () => new Promise((resolve) => {
mountModal(<AudioModalContainer resolve={resolve} />);
});
const openVideoPreviewModal = () => new Promise((resolve) => {
2019-05-24 00:47:56 +08:00
if (userWebcam) return resolve();
mountModal(<VideoPreviewContainer resolve={resolve} />);
});
if (Service.isConnected() && !Service.isListenOnly()) {
Service.updateAudioConstraints(microphoneConstraints);
if (userMic && !Service.isMuted()) {
Service.toggleMuteMicrophone();
notify(intl.formatMessage(intlMessages.reconectingAsListener), 'info', 'audio_on');
}
2018-07-10 03:23:16 +08:00
}
Breakouts.find().observeChanges({
removed() {
// if the user joined a breakout room, the main room's audio was
// programmatically dropped to avoid interference. On breakout end,
// offer to rejoin main room audio only if the user is not in audio already
if (Service.isUsingAudio()
|| userSelectedMicrophone
|| userSelectedListenOnly) {
if (enableVideo && autoShareWebcam) {
openVideoPreviewModal();
}
return;
}
setTimeout(() => openAudioModal().then(() => {
if (enableVideo && autoShareWebcam) {
openVideoPreviewModal();
}
}), 0);
},
});
2017-08-04 20:24:57 +08:00
2017-03-28 04:40:44 +08:00
return {
hasBreakoutRooms,
meetingIsBreakout,
userSelectedMicrophone,
userSelectedListenOnly,
2017-05-02 03:52:57 +08:00
init: () => {
Service.init(messages, intl);
const enableVideo = getFromUserSettings('bbb_enable_video', KURENTO_CONFIG.enableVideo);
const autoShareWebcam = getFromUserSettings('bbb_auto_share_webcam', KURENTO_CONFIG.autoShareWebcam);
if ((!autoJoin || didMountAutoJoin)) {
if (enableVideo && autoShareWebcam) {
openVideoPreviewModal();
}
return;
}
Session.set('audioModalIsOpen', true);
if (enableVideo && autoShareWebcam) {
2019-05-08 03:49:32 +08:00
openAudioModal().then(() => { openVideoPreviewModal(); didMountAutoJoin = true; });
} else if (!(
userSelectedMicrophone
&& userSelectedListenOnly
&& meetingIsBreakout)) {
openAudioModal();
didMountAutoJoin = true;
}
2017-05-02 03:52:57 +08:00
},
2017-03-28 04:40:44 +08:00
};
2019-05-24 00:47:56 +08:00
})(AudioContainer))));
AudioContainer.propTypes = {
hasBreakoutRooms: PropTypes.bool.isRequired,
meetingIsBreakout: PropTypes.bool.isRequired,
userSelectedListenOnly: PropTypes.bool.isRequired,
userSelectedMicrophone: PropTypes.bool.isRequired,
};